use std::{fs, process::Command, sync::OnceLock};
use super::wasm_path::WasmPath;
const WASM_FEATURES: &[&str] = &[
"--enable-bulk-memory",
"--enable-bulk-memory-opt",
"--enable-nontrapping-float-to-int",
"--enable-sign-ext",
"--enable-mutable-globals",
"--enable-reference-types",
"--enable-multivalue",
];
const OPT_LEVEL: &str = "-Os";
pub fn run_wasm_opt(from: &WasmPath, to: &WasmPath) -> bool {
let from_str = from.as_string();
let to_str = to.as_string();
let mut wasm_opt_command = Command::new("wasm-opt");
wasm_opt_command.args(supported_features());
wasm_opt_command.args([OPT_LEVEL, "--strip-debug", "-o", &to_str, &from_str]);
log::info!("Running: {wasm_opt_command:?}");
let wasm_opt_status = wasm_opt_command.status();
match wasm_opt_status {
Ok(status) if status.success() => {
let in_size = size(&from_str);
let out_size = size(&to_str);
let percent = 100 * out_size / in_size;
log::info!("WASM optimized: {in_size}K -> {out_size}K ({percent}%)");
true
}
Ok(_) => {
log::error!("WASM optimization failed");
false
}
Err(error) => {
log::error!(
r#"
WARNING: Can't perform wasm-opt: {error}
Your WASM package will be left unoptimized.
HINT: If you don't have "wasm-opt" command in your system,
install Binaryen package: https://github.com/WebAssembly/binaryen
"#
);
false
}
}
}
fn supported_features() -> &'static Vec<&'static str> {
static FEATURES: OnceLock<Vec<&'static str>> = OnceLock::new();
FEATURES.get_or_init(|| {
let help = Command::new("wasm-opt").arg("--help").output();
let help = match help {
Ok(output) => {
let mut help = String::from_utf8_lossy(&output.stdout).into_owned();
help.push_str(&String::from_utf8_lossy(&output.stderr));
help
}
Err(_) => return Vec::new(),
};
WASM_FEATURES
.iter()
.copied()
.filter(|feature| help.contains(feature))
.collect()
})
}
fn size(path: &str) -> u64 {
fs::metadata(path)
.map(|md| md.len() / 1_024)
.unwrap_or_default()
}