🥹
TinyGo でビルドしたWebAssemblyバイナリが JavaScript 側で呼び込めない時の対応
はじめに
go build
で wasm をビルドして動かしていたものを TinyGo でビルドするように置き換えた際、 JavaScript での読み込みエラーが出たのでその解決策まとめです。
状況
Go で wasm コンパイルをする場合、以下のようにコマンドを実行すると .wasm
バイナリをビルドできます。
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" ./wasm_exec.js
GOOS=js GOARCH=wasm go build -o output.wasm ./main.go
wasm_exec.js
は、JavaScript 側で wasm を読み込むローダーです。 .wasm
をビルドした環境専用のものなのなので、 go env GOROOT
から引っ張って来る必要があります。
このビルドを TinyGo を使ったものに置き換えたい場合、 TinyGo公式を参考にし、
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" ./wasm_exec.js
tinygo build -o output.wasm -target wasm ./main.go
とすると、ビルドは通りますが、ブラウザコンソール上で、以下のような wasm 読み込みをするときにエラーが起きました。
WebAssembly.instantiateStreaming(
fetch('output.wasm'),
go.importObject,
).then((result) => {
go.run(result.instance)
// ...
})
起きたエラー
TypeError: WebAssembly.instantiate(): Import #0 module="wasi_snapshot_preview1" error: module is not an object or function
解決策
tinygo の issue に同じ事象に当たった人がいましたが、 そこについていたコメント の通りにするとうまく読み込みできるようになりました。
読み込み用のローダーの JavaScript も TinyGo のものに置き換える必要があったということです。
# 元々: cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" ./wasm_exec.js
cp "$(tinygo env TINYGOROOT)/targets/wasm_exec.js" ./wasm_exec.js
最終的なコード
こんな感じになりました。
cp "$(tinygo env TINYGOROOT)/targets/wasm_exec.js" ./wasm_exec.js
tinygo build -o output.wasm -target wasm ./main.go
教訓
GitHub の issue が全て解決する
Discussion