Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate wasm-opt into the CLI #2434

Merged
merged 3 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 54 additions & 0 deletions packages/cli-config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ impl Default for DioxusConfig {
cert_path: None,
},
pre_compress: true,
wasm_opt: Default::default(),
},
bundle: BundleConfig {
identifier: Some(format!("io.github.{name}")),
Expand Down Expand Up @@ -281,6 +282,55 @@ pub struct WebConfig {
/// Whether to enable pre-compression of assets and wasm during a web build in release mode
#[serde(default = "true_bool")]
pub pre_compress: bool,
/// The wasm-opt configuration
#[serde(default)]
pub wasm_opt: WasmOptConfig,
}

/// The wasm-opt configuration
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct WasmOptConfig {
/// The wasm-opt level to use for release builds [default: s]
/// Options:
/// - z: optimize aggressively for size
/// - s: optimize for size
/// - 1: optimize for speed
/// - 2: optimize for more for speed
/// - 3: optimize for even more for speed
/// - 4: optimize aggressively for speed
#[serde(default)]
pub level: WasmOptLevel,

/// Keep debug symbols in the wasm file
#[serde(default = "false_bool")]
pub debug: bool,
}

/// The wasm-opt level to use for release web builds [default: 4]
#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize)]
pub enum WasmOptLevel {
/// Optimize aggressively for size
#[serde(rename = "z")]
Z,
/// Optimize for size
#[serde(rename = "s")]
S,
/// Don't optimize
#[serde(rename = "0")]
Zero,
/// Optimize for speed
#[serde(rename = "1")]
One,
/// Optimize for more for speed
#[serde(rename = "2")]
Two,
/// Optimize for even more for speed
#[serde(rename = "3")]
Three,
/// Optimize aggressively for speed
#[serde(rename = "4")]
#[default]
Four,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -582,3 +632,7 @@ impl CrateConfig {
fn true_bool() -> bool {
true
}

fn false_bool() -> bool {
false
}
1 change: 1 addition & 0 deletions packages/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ env_logger = "0.11.3"

tracing-subscriber = { version = "0.3.18", features = ["std", "env-filter"] }
tracing = { workspace = true }
wasm-opt = "0.116.1"

# on maco, we need to specify the vendored feature on ssl when cross compiling
[target.'cfg(target_os = "macos")'.dependencies]
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/src/assets/dioxus.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ asset_dir = "public"
# hot reload by default
hot_reload = true

[web.wasm_opt]
# The level wasm-opt should target. z is the smallest. 4 is the fastest.
level = "4"

[web.app]

# HTML title tag content
Expand Down
80 changes: 37 additions & 43 deletions packages/cli/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
};
use anyhow::Context;
use cargo_metadata::{diagnostic::Diagnostic, Message};
use dioxus_cli_config::{crate_root, CrateConfig, ExecutableType};
use dioxus_cli_config::{crate_root, CrateConfig, ExecutableType, WasmOptLevel};
use indicatif::{ProgressBar, ProgressStyle};
use lazy_static::lazy_static;
use manganis_cli_support::{AssetManifest, ManganisSupportGuard};
Expand Down Expand Up @@ -174,15 +174,18 @@ pub fn build_web(
// [3] Bindgen the final binary for use easy linking
let mut bindgen_builder = Bindgen::new();

let keep_debug = dioxus_config.web.wasm_opt.debug || (!config.release);

bindgen_builder
.input_path(&input_path)
.web(true)
.unwrap()
.debug(true)
.demangle(true)
.keep_debug(true)
.remove_name_section(false)
.remove_producers_section(false)
.debug(keep_debug)
.demangle(keep_debug)
.keep_debug(keep_debug)
.reference_types(true)
.remove_name_section(!keep_debug)
.remove_producers_section(!keep_debug)
.out_name(&dioxus_config.application.name)
.generate(&bindgen_outdir)
.unwrap();
Expand All @@ -197,43 +200,33 @@ pub fn build_web(
run_wasm_bindgen();
}

// check binaryen:wasm-opt tool
tracing::info!("Running optimization with wasm-opt...");
let dioxus_tools = dioxus_config.application.tools.clone();
if dioxus_tools.contains_key("binaryen") {
let info = dioxus_tools.get("binaryen").unwrap();
let binaryen = crate::tools::Tool::Binaryen;

if binaryen.is_installed() {
if let Some(sub) = info.as_table() {
if sub.contains_key("wasm_opt")
&& sub.get("wasm_opt").unwrap().as_bool().unwrap_or(false)
{
tracing::info!("Optimizing WASM size with wasm-opt...");
let target_file = out_dir
.join("assets")
.join("dioxus")
.join(format!("{}_bg.wasm", dioxus_config.application.name));
if target_file.is_file() {
let mut args = vec![
target_file.to_str().unwrap(),
"-o",
target_file.to_str().unwrap(),
];
if config.release {
args.push("-Oz");
}
binaryen.call("wasm-opt", args)?;
}
}
}
} else {
tracing::warn!(
"Binaryen tool not found, you can use `dx tool add binaryen` to install it."
);
}
} else {
tracing::info!("Skipping optimization with wasm-opt, binaryen tool not found.");
// Run wasm-opt if this is a release build
if config.release {
tracing::info!("Running optimization with wasm-opt...");
let mut options = match dioxus_config.web.wasm_opt.level {
WasmOptLevel::Z => wasm_opt::OptimizationOptions::new_optimize_for_size_aggressively(),
WasmOptLevel::S => wasm_opt::OptimizationOptions::new_optimize_for_size(),
WasmOptLevel::Zero => wasm_opt::OptimizationOptions::new_opt_level_0(),
WasmOptLevel::One => wasm_opt::OptimizationOptions::new_opt_level_1(),
WasmOptLevel::Two => wasm_opt::OptimizationOptions::new_opt_level_2(),
WasmOptLevel::Three => wasm_opt::OptimizationOptions::new_opt_level_3(),
WasmOptLevel::Four => wasm_opt::OptimizationOptions::new_opt_level_4(),
};
let wasm_file = bindgen_outdir.join(format!("{}_bg.wasm", dioxus_config.application.name));
let old_size = wasm_file.metadata()?.len();
options
// WASM bindgen relies on reference types
.enable_feature(wasm_opt::Feature::ReferenceTypes)
.debug_info(dioxus_config.web.wasm_opt.debug)
.run(&wasm_file, &wasm_file)
.map_err(|err| Error::Other(anyhow::anyhow!(err)))?;
let new_size = wasm_file.metadata()?.len();
tracing::info!(
"wasm-opt reduced WASM size from {} to {} ({:2}%)",
old_size,
new_size,
(new_size as f64 - old_size as f64) / old_size as f64 * 100.0
);
}

// If pre-compressing is enabled, we can pre_compress the wasm-bindgen output
Expand All @@ -242,6 +235,7 @@ pub fn build_web(
}

// [5][OPTIONAL] If tailwind is enabled and installed we run it to generate the CSS
let dioxus_tools = dioxus_config.application.tools.clone();
if dioxus_tools.contains_key("tailwindcss") {
let info = dioxus_tools.get("tailwindcss").unwrap();
let tailwind = crate::tools::Tool::Tailwind;
Expand Down
Loading
Loading