← 文章 開發感想

Cloudflare Workers 部署 50MB WASM 的踩坑記錄

記錄將一個 50MB 的八字演算 WASM 部署到 Cloudflare Workers 的完整過程,以及如何用 Brotli 壓縮解決文件大小限制。

術數工具

基於 WebAssembly & 原生 iOS,探索星曆之美

Cloudflare Workers 有一個隱藏的限制:單個靜態資源文件不能超過 25MB

我的八字演算 WASM 文件有 50MB。

這是一個需要解決的問題。

問題分析

WASM 文件大的原因很簡單:八字演算需要內置大量的曆法數據(節氣精確時刻、真太陽時修正係數等),這些數據被直接編譯進了二進制文件。

解決方案有三種:

  1. 拆分數據:將曆法數據從 WASM 中剝離,作爲獨立的 JSON 文件按需加載。
  2. 壓縮傳輸:保持 WASM 不變,使用 Brotli 或 Gzip 壓縮後傳輸,瀏覽器自動解壓。
  3. 換平臺:使用支持更大文件的存儲服務(如 R2)託管 WASM。

方案一改動最大,需要修改 Rust 源碼。方案三引入了額外的複雜度。我選擇了方案二。

Brotli 壓縮的效果

# 原始大小
ls -lh ganzhi.wasm
# -rwxr-xr-x  50M  ganzhi.wasm

# Brotli 壓縮
brotli -q 11 ganzhi.wasm -o ganzhi.wasm.br
ls -lh ganzhi.wasm.br
# -rwxr-xr-x  12M  ganzhi.wasm.br

壓縮率達到 76%,12MB 完全在 Cloudflare 的 25MB 限制之內。

Worker 配置

關鍵在於 Worker 需要爲 .wasm.br 文件設置正確的響應頭,告訴瀏覽器這是一個 Brotli 壓縮的 WASM 文件:

if (pathname.endsWith('.wasm.br')) {
  const response = await env.ASSETS.fetch(request);
  const headers = new Headers(response.headers);
  headers.set('Content-Type', 'application/wasm');
  headers.set('Content-Encoding', 'br');
  headers.set('Cache-Control', 'public, max-age=86400');
  return new Response(response.body, { status: response.status, headers });
}

瀏覽器收到 Content-Encoding: br 後,會自動解壓並將結果作爲 WASM 傳遞給 WebAssembly.instantiate()。整個過程對前端代碼完全透明。

結果

最終部署成功,八字演算工具正常運行。用戶下載的是 12MB 的壓縮文件,瀏覽器解壓後得到 50MB 的 WASM,整個過程約需 5-15 秒(取決於網絡速度)。

有時候,最優雅的解決方案不是重構,而是在正確的地方加一個正確的響應頭。


相關工具已部署上線,可以在上方的「八字命盤」入口體驗完整演算功能。