diff --git a/crates/maestro-web/build.rs b/crates/maestro-web/build.rs index 2549375..61570cc 100644 --- a/crates/maestro-web/build.rs +++ b/crates/maestro-web/build.rs @@ -27,6 +27,16 @@ fn main() { println!("cargo:rerun-if-changed={}", web_dir.join(rel).display()); } + // Also watch the embedded OUTPUT directory. The input watches above decide + // whether THIS script re-runs and regenerates `web/dist`; but `include_dir!` + // in `static_bundle.rs` reads `web/dist`, and cargo has no other declared + // dependency on those output files. Without this watch, an incremental build + // could regenerate `web/dist` yet keep the OLD bundle embedded. Tying the + // crate's recompilation to the regenerated output makes the fresh assets + // actually get re-embedded. + let dist_dir = web_dir.join("dist"); + println!("cargo:rerun-if-changed={}", dist_dir.display()); + require_tool("pnpm"); require_tool("node"); @@ -40,6 +50,21 @@ fn main() { Command::new("pnpm").arg("build").current_dir(&web_dir), "pnpm build", ); + + // Sanity-check that pnpm build actually produced the bundle `include_dir!` + // expects. A green build that embeds an empty/placeholder dir is worse than + // a loud failure here. + let index_html = dist_dir.join("index.html"); + let produced = std::fs::metadata(&index_html) + .map(|m| m.is_file() && m.len() > 0) + .unwrap_or(false); + if !produced { + panic!( + "`pnpm build` did not produce the expected bundle at {} \ + (missing or empty) — check the vite `outDir`.", + index_html.display() + ); + } } fn require_tool(tool: &str) { diff --git a/crates/maestro-web/tests/embedded_bundle.rs b/crates/maestro-web/tests/embedded_bundle.rs index 0448f43..4bd3c06 100644 --- a/crates/maestro-web/tests/embedded_bundle.rs +++ b/crates/maestro-web/tests/embedded_bundle.rs @@ -18,4 +18,12 @@ async fn embedded_index_is_real_spa_not_placeholder() { !html.contains("maestro-web is running"), "served index is the placeholder, not the built bundle" ); + // Stronger signal than `id="app"` (which appears in both source and built + // HTML): the vite build rewrites the entry to a hashed `/assets/index-` + // bundle, whereas the un-built source references `/src/main.ts`. This catches + // both an empty/placeholder embed and the staleness case. + assert!( + html.contains("/assets/index-"), + "served index does not reference a vite-built hashed asset; got:\n{html}" + ); }