Cloudflare Workers 部署 50MB WASM 的踩坑记录
记录将一个 50MB 的八字演算 WASM 部署到 Cloudflare Workers 的完整过程,以及如何用 Brotli 压缩解决文件大小限制。
Cloudflare Workers 有一个隐藏的限制:单个静态资源文件不能超过 25MB。
我的八字演算 WASM 文件有 50MB。
这是一个需要解决的问题。
问题分析
WASM 文件大的原因很简单:八字演算需要内置大量的历法数据(节气精确时刻、真太阳时修正系数等),这些数据被直接编译进了二进制文件。
解决方案有三种:
- 拆分数据:将历法数据从 WASM 中剥离,作为独立的 JSON 文件按需加载。
- 压缩传输:保持 WASM 不变,使用 Brotli 或 Gzip 压缩后传输,浏览器自动解压。
- 换平台:使用支持更大文件的存储服务(如 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 秒(取决于网络速度)。
有时候,最优雅的解决方案不是重构,而是在正确的地方加一个正确的响应头。
相关工具已部署上线,可以在上方的「八字命盘」入口体验完整演算功能。