Skip to content

Commit

Permalink
Optimize binary with wasm-opt in release mode (#206)
Browse files Browse the repository at this point in the history
# Objective

Closes #196, unblocks
<TheBevyFlock/bevy_new_2d#312>.

With `wasm-opt`, we can further increase the performance and reduce the
file size of the Wasm binary we use for web builds.
This speeds ups the app both in-game and the loading times.

# Solution

As a simple first solution, we add a hard-coded size optimization pass
in release mode.
In future PRs, we can make this more configurable.

To the user, we log the time the optimization took as well as the file
size reduction as percentage.

This is behind the `wasm-opt` feature flag (currently disabled by
default), to give the user a way to turn this off and because this
increases compile times of the CLI quite a bit.
  • Loading branch information
TimJentzsch authored Dec 29, 2024
1 parent 5d99f41 commit 4e740c7
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 28 deletions.
238 changes: 210 additions & 28 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ default-run = "bevy"
name = "bevy"
path = "src/bin/main.rs"

[features]
# To optimize the Wasm binaries
# Increases compile times (of the CLI) quite a bit
wasm-opt = ["dep:wasm-opt"]

[dependencies]
# CLI argument parsing
clap = { version = "4.5.16", features = ["derive"] }
Expand Down Expand Up @@ -42,3 +47,6 @@ actix-web = "4.9.0"

# Opening the app in the browser
webbrowser = "1.0.2"

# Optimizing Wasm binaries
wasm-opt = { version = "0.116.1", optional = true }
6 changes: 6 additions & 0 deletions src/build/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ impl BuildArgs {
matches!(self.subcommand, Some(BuildSubcommands::Web))
}

/// Whether to build with optimizations.
#[cfg(feature = "wasm-opt")]
pub(crate) fn is_release(&self) -> bool {
self.cargo_args.compilation_args.is_release
}

/// The profile used to compile the app.
pub(crate) fn profile(&self) -> &str {
self.cargo_args.compilation_args.profile()
Expand Down
5 changes: 5 additions & 0 deletions src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ pub fn build(args: &BuildArgs) -> anyhow::Result<()> {
args.profile(),
)?;
wasm_bindgen::bundle(&bin_target)?;

#[cfg(feature = "wasm-opt")]
if args.is_release() {
crate::web::wasm_opt::optimize_bin(&bin_target)?;
}
} else {
cargo::build::command().args(cargo_args).ensure_status()?;
}
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ pub mod external_cli;
pub mod lint;
pub mod run;
pub mod template;
pub(crate) mod web;
6 changes: 6 additions & 0 deletions src/run/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ impl RunArgs {
matches!(self.subcommand, Some(RunSubcommands::Web(_)))
}

/// Whether to build with optimizations.
#[cfg(feature = "wasm-opt")]
pub(crate) fn is_release(&self) -> bool {
self.cargo_args.compilation_args.is_release
}

/// The profile used to compile the app.
pub(crate) fn profile(&self) -> &str {
self.cargo_args.compilation_args.profile()
Expand Down
5 changes: 5 additions & 0 deletions src/run/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ pub fn run(args: &RunArgs) -> anyhow::Result<()> {
)?;
wasm_bindgen::bundle(&bin_target)?;

#[cfg(feature = "wasm-opt")]
if args.is_release() {
crate::web::wasm_opt::optimize_bin(&bin_target)?;
}

let port = web_args.port;
let url = format!("http://localhost:{port}");

Expand Down
2 changes: 2 additions & 0 deletions src/web/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#[cfg(feature = "wasm-opt")]
pub(crate) mod wasm_opt;
38 changes: 38 additions & 0 deletions src/web/wasm_opt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use std::{fs, path::Path, time::Instant};

use anyhow::Context as _;

use crate::run::BinTarget;

/// Optimize the binary with wasm-opt.
pub(crate) fn optimize_bin(bin_target: &BinTarget) -> anyhow::Result<()> {
let wasm_path = bin_target
.artifact_directory
.clone()
.join(format!("{}_bg.wasm", bin_target.bin_name));

optimize_path(&wasm_path)
}

/// Optimize the Wasm binary at the given path with wasm-opt.
fn optimize_path(path: &Path) -> anyhow::Result<()> {
println!("Optimizing with wasm-opt...");

let start = Instant::now();
let size_before = fs::metadata(path)?.len();

wasm_opt::OptimizationOptions::new_optimize_for_size()
.run(path, path)
.context("failed to optimize with wasm-opt")?;

let size_after = fs::metadata(path)?.len();
let size_reduction = 1. - (size_after as f32) / (size_before as f32);
let duration = start.elapsed();

println!(
" Finished in {duration:.2?}. Size reduced by {:.0}%.",
size_reduction * 100.
);

Ok(())
}

0 comments on commit 4e740c7

Please sign in to comment.