iT邦幫忙

2025 iThome 鐵人賽

DAY 15
0
Rust

把前端加速到天花板:Rust+WASM 即插即用外掛系列 第 15

Day 15|為什麼 .wasm 會變胖?怎麼減?Cargo 與 wasm-opt 的分工

  • 分享至 

  • xImage
  •  

前幾天我們把功能越寫越多(多個濾鏡、錯誤格式、Worker 版…),結果 pkg/*.wasm 越來越胖。今天把體重管理講清楚:哪裡在長肉、誰負責減肥、怎麼操作。其實就是把 Cargo/LLVM 做「Rust→機器碼階段」的最佳化,wasm-opt 做二次瘦身。

為什麼會變胖?

  • Dev 組態wasm-pack build 預設是 dev(無 LTO、較少最佳化、帶除錯資訊)。
  • panic 展開 & 格式化字串panic! / format! 會把一大坨 core::fmt、展開流程拉進來。
  • 相依套件的預設 featuresweb-sys / serde / 其他 crates 的「全功能」常把用不到的符號也編進來。
  • JS glue + 型別資訊wasm-bindgen 產生的 glue/型別描述若不最小化,也會占空間。
  • Wasm 層級的小廢肉:重複基本塊、沒用到的匯出、無意義的 local、DWARF/producer 區段等。

先量:你得知道胖在哪

  • 粗量:ls -lh pkg/*.wasm
  • or:
    • cargo install twiggytwiggy top pkg/xxx_bg.wasm(誰佔最大)
    • wasm-tools size pkg/xxx_bg.wasm(各 section 大小)
  • 連 JS 一起看:du -h pkg/*(glue + wasm)

Cargo/LLVM 層 → 產生更瘦的 Wasm

Cargo.toml 加下列 release 組態:

# Cargo.toml
[profile.release]
opt-level = "z"        # 比 "s" 更追求小
lto = "fat"            # 跨 crate 最佳化,通常顯著變小
codegen-units = 1      # 讓 LLVM 看得到整體(更好 DCE/內聯)
panic = "abort"        # 砍掉 unwind 機制與相關表
strip = "symbols"      # 去除符號(Rust 1.70+ 穩定),或用 true 也行
debug = false          # 確保不帶 DWARF

[dependencies]
# 盡量關掉不需要的 default features
serde = { version = "1", default-features = false, features = ["derive"] }
serde-wasm-bindgen = "0.6"
wasm-bindgen = { version = "0.2", default-features = false }
# web-sys / js-sys 只開用到的功能(如果有用到才加)
# web-sys = { version = "0.3", features = ["Window"] }

程式碼層的小調整(只新增的部分)

// 在 lib.rs 最上面:release 版不要掛 panic hook,避免拉進 fmt
#[cfg(debug_assertions)]
#[wasm_bindgen(start)]
pub fn set_panic_hook() {
    console_error_panic_hook::set_once();
}

// 錯誤訊息盡量用短字串;避免 format! 拼長句(會拉進 core::fmt)

Tip:f32 足夠時別用 f64;不要濫用 Debug/Display;可把大型常數表改為運算生成或壓縮儲存。

wasm-opt 層(對成品再做手術)

wasm-opt 是 Binaryen 的工具,對已產出的 .wasm做 peephole/DCE/inline/合併基本塊/剝除區段等。

最常用一條:

# 安裝:brew install binaryen  或  npm i -g binaryen
wasm-opt -Oz --strip-debug --strip-producers -o pkg/xxx_bg.wasm pkg/xxx_bg.wasm
  • Oz:極致瘦身(比 Os 更激進)。
  • -strip-debug --strip-producers:移除除錯/編譯器資訊。
  • 加速版可試:Os;想更狠可加 -dce --merge-blocks --vacuum(通常 Oz 已涵蓋)。

wasm-pack 會自動幫你跑 wasm-opt(如果系統有裝):用

wasm-pack build --target web --release

就會觸發。沒裝的話,自己補跑一次上面那條。

可以直接貼

# 1) 乾淨重建
rm -rf pkg target
wasm-pack build --target web --release    # 若裝了 binaryen,會自動調用 wasm-opt

# 2) 若沒自動跑到 wasm-opt,再補刀一次
wasm-opt -Oz --strip-debug --strip-producers \
  -o pkg/rustwasm_test_bg.wasm pkg/rustwasm_test_bg.wasm

# 3) 檢查體積
ls -lh pkg/*.wasm
# 4) 看熱點
twiggy top pkg/rustwasm_test_bg.wasm | head -n 20

https://ithelp.ithome.com.tw/upload/images/20250929/20162491j8Xq9MyOE3.png


上一篇
Day 13|人多力量大! Web Worker 多工 + 佇列
下一篇
Day 16|把 memory bound 的坑填起來
系列文
把前端加速到天花板:Rust+WASM 即插即用外掛18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言