🙌

Emscripten wasm を zstd 圧縮して読み込むメモ

に公開

Emscripten で WASM module 作ったけど 2 MB くらいある.
圧縮してファイルサイズ減らしたい...
2025 年ですと zstd 圧縮がメインですから, zstd 使います.

tinyusdz の例では 2MB -> 400kb になりました.

背景

Emscripten(emcc) で -sMODULE -sEXPORT_ES6 有効にしているとする.

この場合, 例えば tinyusdz.js(ブートストラップ)と tinyusdz.wasm ができて,

import initTinyUSDZNative from './tinyusdz.js';

let mod = await initTinyUSDZNative({});

こんな感じで初期化すると内部で wasm を読んでくれる.

tinyusdz.wasm ファイル名は tinyusdz.js の内部にハードコードされているので, 圧縮した wasm を扱う場合, tinyusdz.js をいじらなければならないか... と思いますが, 幸いにも引数で wasmBinary(Uint8Array) を与えてあげるとそちらを読むようになっている.

zstd npm package

ブラウザ(client)では decompress だけあればよい. fzstd か zstddec あたりがメジャーであろうか.

fzstd は Pure JS 実装, zstddec は C コードを WASM 化.
(fzstd 24KB, zstddec 34 KB くらい)

方法

import { decompress } from 'fzstd'; // or your preferred zstd library
import initTinyUSDZNative from './tinyusdz.js';

    // Decompress zstd compressed WASM
    async decompressZstdWasm(compressedPath) {
        try {
            console.log(`Loading compressed WASM from: ${compressedPath}`);
            const response = await fetch(compressedPath);
            if (!response.ok) {
                throw new Error(`Failed to fetch compressed WASM: ${response.statusText}`);
            }
            
            const compressedData = await response.arrayBuffer();
            console.log(`Compressed WASM size: ${compressedData.byteLength} bytes`);
            
            // Decompress using zstd
            const decompressedData = decompress(new Uint8Array(compressedData));
            console.log(`Decompressed WASM size: ${decompressedData.byteLength} bytes`);
            
            return decompressedData;
        } catch (error) {
            console.error('Error decompressing zstd WASM:', error);
            throw error;
        }
    }

    let wasmBinary = await this.decompressZstdWasm("./tinyusdz.wasm.zstd");
    const initOptions = wasmBinary ? { wasmBinary } : {};
            
    let mod = await initTinyUSDZNative(initOptions);

こんな感じでいけます!

zstd -19 で tinyusdz.wasm を圧縮したら 400 KB(元は 2 MB くらい)になりました.
19は圧縮レベルかなり高いほうですが, 数MBくらいなら decode 速度にそれほど影響ないと思います.
(圧縮も 2,3 秒くらい)

さらなる高みへ

詳しいことは Claude 4 くんや ChatGPT くんに聞いて

Discussion