← 記事 個人開発 · チュートリアル

Cloudflare Workers に 50MB の WASM をデプロイした時のハマりどころメモ

50MB の八字演算 WASM を Cloudflare Workers にデプロイした全プロセスと、Brotli 圧縮によるファイルサイズ制限の解決方法の記録。

Cloudflare Workers には隠れた制限があります:単一の静的リソースファイルは 25MB を超えられません

私の八字演算 WASM ファイルは 50MB もあります。

これは解決すべき問題です。

問題の分析

WASM ファイルが大きい理由は簡単です:八字演算には大量の暦データ(節気の正確な時刻、真太陽時補正係数など)を内蔵する必要があり、これらのデータがバイナリファイルに直接コンパイルされているからです。

解決策は3つあります:

  1. データの分割:暦データを WASM から分離し、独立した JSON ファイルとして必要に応じて読み込む。
  2. 圧縮転送:WASM はそのままに、Brotli または Gzip で圧縮して転送し、ブラウザが自動的に解凍する。
  3. プラットフォームの変更:より大きなファイルに対応したストレージサービス(R2 など)で WASM をホスティングする。

案1は変更量が最も大きく、Rust のソースコードを修正する必要があります。案3は追加の複雑さを招きます。私は案2を選びました。

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秒かかります(ネットワーク速度によります)。

時には、最もエレガントな解決策はリファクタリングではなく、正しい場所に正しいレスポンスヘッダーを追加することです。


関連ツールはすでにデプロイ済みで、上部の「八字命盤」エントリーから完全な演算機能を試すことができます。