105 lines
3.2 KiB
Rust
105 lines
3.2 KiB
Rust
|
|
//! Builds the Solid management UI for embedded Release binaries.
|
||
|
|
//!
|
||
|
|
//! Debug builds intentionally return before invoking npm: during development
|
||
|
|
//! Vite serves `web/` independently and proxies its API client to the Rust
|
||
|
|
//! listener. Release builds use the lockfile, write only into Cargo `OUT_DIR`,
|
||
|
|
//! and expose a cfg consumed by `src/web.rs`. The source tree therefore never
|
||
|
|
//! needs a generated `dist/` for `cargo build --release`.
|
||
|
|
//!
|
||
|
|
//! Set `WASMELD_BUILD_WEB=1` to exercise the embedded path in another Cargo
|
||
|
|
//! profile, or `NPM=/absolute/path/to/npm` when npm is not on `PATH`.
|
||
|
|
|
||
|
|
use std::{
|
||
|
|
env, fs,
|
||
|
|
path::PathBuf,
|
||
|
|
process::{Command, ExitStatus},
|
||
|
|
};
|
||
|
|
|
||
|
|
const WEB_INPUTS: &[&str] = &[
|
||
|
|
"web/src",
|
||
|
|
"web/public",
|
||
|
|
"web/index.html",
|
||
|
|
"web/page.html",
|
||
|
|
"web/package.json",
|
||
|
|
"web/package-lock.json",
|
||
|
|
"web/tsconfig.json",
|
||
|
|
"web/vite.config.ts",
|
||
|
|
];
|
||
|
|
|
||
|
|
fn main() {
|
||
|
|
println!("cargo:rustc-check-cfg=cfg(wasmeld_embedded_web)");
|
||
|
|
println!("cargo:rerun-if-env-changed=WASMELD_BUILD_WEB");
|
||
|
|
println!("cargo:rerun-if-env-changed=NPM");
|
||
|
|
for input in WEB_INPUTS {
|
||
|
|
println!("cargo:rerun-if-changed={input}");
|
||
|
|
}
|
||
|
|
|
||
|
|
let force = env::var("WASMELD_BUILD_WEB").is_ok_and(|value| value == "1");
|
||
|
|
if env::var("PROFILE").as_deref() != Ok("release") && !force {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
let crate_dir = PathBuf::from(required_env("CARGO_MANIFEST_DIR"));
|
||
|
|
let web_dir = crate_dir.join("web");
|
||
|
|
let output_dir = PathBuf::from(required_env("OUT_DIR")).join("web");
|
||
|
|
let npm = env::var_os("NPM")
|
||
|
|
.map(PathBuf::from)
|
||
|
|
.unwrap_or_else(|| PathBuf::from(if cfg!(windows) { "npm.cmd" } else { "npm" }));
|
||
|
|
|
||
|
|
if output_dir.exists() {
|
||
|
|
fs::remove_dir_all(&output_dir).unwrap_or_else(|error| {
|
||
|
|
panic!(
|
||
|
|
"failed to clear embedded Web output {}: {error}",
|
||
|
|
output_dir.display()
|
||
|
|
)
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// `npm ci` is deliberate here: a release must not silently rewrite the
|
||
|
|
// dependency graph represented by package-lock.json.
|
||
|
|
run(
|
||
|
|
Command::new(&npm).current_dir(&web_dir).args([
|
||
|
|
"ci",
|
||
|
|
"--ignore-scripts",
|
||
|
|
"--no-audit",
|
||
|
|
"--no-fund",
|
||
|
|
]),
|
||
|
|
"install locked Web dependencies",
|
||
|
|
);
|
||
|
|
run(
|
||
|
|
Command::new(&npm)
|
||
|
|
.current_dir(&web_dir)
|
||
|
|
.env("WASMELD_WEB_OUT_DIR", &output_dir)
|
||
|
|
.args(["run", "build"]),
|
||
|
|
"build embedded Web application",
|
||
|
|
);
|
||
|
|
|
||
|
|
for required in ["index.html", "page.html", "sw.js", "manifest.webmanifest"] {
|
||
|
|
let path = output_dir.join(required);
|
||
|
|
assert!(
|
||
|
|
path.is_file(),
|
||
|
|
"Web build did not produce required asset {}",
|
||
|
|
path.display()
|
||
|
|
);
|
||
|
|
}
|
||
|
|
println!("cargo:rustc-cfg=wasmeld_embedded_web");
|
||
|
|
}
|
||
|
|
|
||
|
|
fn run(command: &mut Command, action: &str) {
|
||
|
|
let status = command
|
||
|
|
.status()
|
||
|
|
.unwrap_or_else(|error| panic!("failed to {action}: {error}"));
|
||
|
|
assert_success(status, action);
|
||
|
|
}
|
||
|
|
|
||
|
|
fn assert_success(status: ExitStatus, action: &str) {
|
||
|
|
assert!(
|
||
|
|
status.success(),
|
||
|
|
"failed to {action}: process exited with {status}"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
fn required_env(name: &str) -> String {
|
||
|
|
env::var(name).unwrap_or_else(|_| panic!("Cargo did not provide {name}"))
|
||
|
|
}
|