From a940dab72760d706fe8132eecb7e50e0247581d8 Mon Sep 17 00:00:00 2001 From: eliets2 <287273517+eliets2@users.noreply.github.com> Date: Sat, 10 Oct 2026 23:37:52 +0300 Subject: [PATCH] web: stop the release zip shipping Cargo build artifacts lightcraft-web-.zip carried Cargo host build output next to the site: deps/ (81 files, 90.6 MB), build/ (149 files, 22.4 MB) and .fingerprint/ (297 files), ~113 MB that the app never references and that leaked build paths and crate names to anyone hosting the zip. Cause: xtask wrote the bundle to /web (SITE in packaging/web/package.sh) while building with --profile web. Cross-compiling with --target wasm32-unknown-unknown makes Cargo write the selected profile host artifacts (build scripts, proc-macros, deps/, build/, .fingerprint/) to //, so they landed in the bundle directory and package.sh copied the whole tree into the zip. Fix: write the bundle to /web-site, a directory that is not a Cargo profile name, and point SITE at it. The wasm32/web/ target artifacts and the web profile are unchanged, so the rust-cache keys and the CI web job keep working. Guard: package.sh now fails if deps/, build/ or .fingerprint/ exists in $SITE, and a unit test asserts the bundle directory is not a Cargo profile name, so the collision cannot come back silently. Reference (#793) --- docs/web.md | 2 +- packaging/web/package.sh | 12 +++++++++++- xtask/src/main.rs | 2 +- xtask/src/web.rs | 28 +++++++++++++++++++++++++--- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/docs/web.md b/docs/web.md index 2e26f749b..ca0d98434 100644 --- a/docs/web.md +++ b/docs/web.md @@ -18,7 +18,7 @@ it's missing or a different version. Build, then serve: ```sh -cargo xtask web # → /web/{index.html, worker.js, lightcraft_web.js, lightcraft_web_bg.wasm} +cargo xtask web # → /web-site/{index.html, worker.js, lightcraft_web.js, lightcraft_web_bg.wasm} cargo xtask web --serve # build, then serve on http://127.0.0.1:8080/ (or `--serve 9000`) cargo xtask web --dev # unoptimized build with debug info (faster to compile, slow to run) ``` diff --git a/packaging/web/package.sh b/packaging/web/package.sh index 8e8f0cf08..64b6d2149 100755 --- a/packaging/web/package.sh +++ b/packaging/web/package.sh @@ -15,8 +15,18 @@ if [ "${1:-}" != "--skip-build" ]; then (cd "$ROOT" && cargo xtask web) fi -SITE="$CARGO_TARGET_DIR/web" +SITE="$CARGO_TARGET_DIR/web-site" [ -f "$SITE/index.html" ] || { echo "error: $SITE/index.html missing; run without --skip-build" >&2; exit 1; } +# Guard against Cargo build artifacts leaking into the release (issue #793): cross-compiling writes +# the selected profile's *host* artifacts (build scripts, proc-macros, deps/, build/, .fingerprint/) +# to //, so if SITE ever points at a profile directory again the zip would carry +# ~113 MB of build output. Fail loudly instead. +for d in deps build .fingerprint; do + if [ -e "$SITE/$d" ]; then + echo "error: $SITE/$d exists — $SITE holds Cargo build artifacts, not just the site (issue #793)" >&2 + exit 1 + fi +done # Paths must be relative so the site works under any prefix. if grep -Eq '(src|href)="/[^/]' "$SITE/index.html"; then echo "error: $SITE/index.html has root-absolute URLs; it would break when served from a sub-path" >&2 diff --git a/xtask/src/main.rs b/xtask/src/main.rs index cd226d6f2..0d74f93b8 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -31,7 +31,7 @@ commands: Lightroom parity summary; --write refreshes the summary table in the document wasm cargo check --target wasm32-unknown-unknown for the wasm-safe crates (+ the web app) web [--serve [port]] [--dev] - build the browser app (apps/lightcraft-web) into /web/; + build the browser app (apps/lightcraft-web) into /web-site/; --serve serves it on http://127.0.0.1: (default 8080) ci fmt --check, clippy -D warnings, heif, test, parity refs, layers, assets, wasm (stops at first failure) corpus [--download] diff --git a/xtask/src/web.rs b/xtask/src/web.rs index 4e690d634..f10ba489b 100644 --- a/xtask/src/web.rs +++ b/xtask/src/web.rs @@ -1,5 +1,5 @@ //! `cargo xtask web`: build `apps/lightcraft-web` for wasm32 and bundle it with `wasm-bindgen` -//! into `/web/` (index.html + worker.js + lightcraft_web.js + lightcraft_web_bg.wasm), +//! into `/web-site/` (index.html + worker.js + lightcraft_web.js + lightcraft_web_bg.wasm), //! with gzip and brotli precompressed copies (`*.gz`, `*.br`) next to each file. //! `--serve [port]` then serves that folder with a tiny static HTTP server (std only) that sends //! the cross-origin isolation headers (COOP/COEP) and the precompressed files when the browser @@ -13,6 +13,13 @@ use std::process::Command; use crate::{cargo, metadata, root, run as step}; const TARGET: &str = "wasm32-unknown-unknown"; +/// Cargo profile for the optimized (`--dev` off) browser build; see `[profile.web]` in `Cargo.toml`. +const WEB_PROFILE: &str = "web"; +/// Directory under `` that receives the bundle. It must **not** be a Cargo profile name: +/// cross-compiling with `--target wasm32-unknown-unknown` makes Cargo write the selected profile's +/// *host* artifacts (build scripts, proc-macros, `deps/`, `build/`, `.fingerprint/`) to +/// `//`, and `packaging/web/package.sh` zips the whole bundle directory (issue #793). +const SITE_DIR: &str = "web-site"; const CHINESE_FONT_FILE: &str = "lightcraft_zh_hans.otf"; const CHINESE_FONT_LICENSE_FILE: &str = "OFL-noto-sans-cjk-sc.txt"; @@ -100,14 +107,14 @@ pub fn run(args: &[&str]) -> Result<(), String> { check_bindgen(&want)?; let meta = metadata()?; let target_dir = PathBuf::from(meta["target_directory"].as_str().ok_or("cargo metadata: no target_directory")?); - let profile = if dev { "dev" } else { "web" }; + let profile = if dev { "dev" } else { WEB_PROFILE }; let mut c = cargo(); c.args(["build", "-p", "lightcraft-web", "--lib", "--target", TARGET, "--profile", profile]); step(c, &format!("cargo build -p lightcraft-web --target {TARGET} --profile {profile}"))?; let wasm = target_dir.join(TARGET).join(if dev { "debug" } else { profile }).join("lightcraft_web.wasm"); - let out = target_dir.join("web"); + let out = target_dir.join(SITE_DIR); std::fs::create_dir_all(&out).map_err(|e| format!("{}: {e}", out.display()))?; let mut b = Command::new("wasm-bindgen"); b.arg(&wasm).args(["--target", "web", "--no-typescript", "--out-name", "lightcraft_web", "--out-dir"]).arg(&out); @@ -287,6 +294,21 @@ mod tests { assert!(v.starts_with("0.2."), "{v}"); } + #[test] + fn site_dir_is_not_a_cargo_profile() { + // Cross-compiling writes the selected profile's *host* artifacts (build scripts, + // proc-macros, `deps/`, `build/`, `.fingerprint/`) to `//`, so the bundle + // must not live in a profile directory or `packaging/web/package.sh` would zip them + // (issue #793). + let manifest = std::fs::read_to_string(root().join("Cargo.toml")).unwrap(); + let is_profile = |name: &str| { + let header = format!("[profile.{name}]"); + manifest.lines().any(|l| l.trim() == header) + }; + assert!(is_profile(WEB_PROFILE), "`{WEB_PROFILE}` is no longer a profile in Cargo.toml"); + assert!(!is_profile(SITE_DIR), "`{SITE_DIR}` is a Cargo profile name; pick a different bundle directory"); + } + #[test] fn wasm_mime() { assert_eq!(mime(Path::new("a/lightcraft_web_bg.wasm")), "application/wasm");