前回やった内容で「golang webassembly」と検索してもあまり情報がなかったけど、ReactやCordovaとWebAssemblyの組み合わせは全く出てこなかった。
React+Cordovaでアプリを作るテストもしていたので、せっかくだから手探りでアプリ化までしました。
今回はその備忘録です。
GO→WebAssembly
まずは前回に倣ってGOからwasmファイルを作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package main import( "syscall/js" ) func test(jsv []js.Value) { js.Global().Get("window").Call("textCallback","test"+jsv[0].String()) } func setFuncs(){ js.Global().Set("test", js.NewCallback(test)) } func main(){ setFuncs() done := make(chan struct{}, 0) <-done } |
1 |
env GOOS=js GOARCH=wasm go build -o test.wasm test.go |
追加要素で返値としてcallbackを呼び出してます。
このwasmファイルを使って次に進みます。
WebAssembly→React
publicにwasm_exec.jsを置いてindex.htmlで読み込みます。
1 |
<script type="text/javascript" src="wasm_exec.js"></script> |
コンストラクタでgoを読み込むためのクラスをstateに入れます。
1 2 3 4 5 6 |
constructor(props) { super(props); this.state = { go: new window.Go(), }; } |
resolveLocalFileSystemURLを利用してArrayBufferからResponse化します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
let base_in = window.cordova.file.applicationDirectory+'www/static/media/'; window.resolveLocalFileSystemURL( base_in+"text.wasm", (entry)=>{ entry.file( (f)=>{ let reader = new FileReader(); reader.onloadend = function(evt){ const go = this.state.go; let wr = new Response(reader.result,{"headers":{'Content-Type':'application/wasm'}}); WebAssembly.instantiateStreaming(wr, go.importObject).then((result) => { let mod = result.module; let inst = result.instance; (async () => { await go.run(inst); inst = await WebAssembly.instantiate(mod, go.importObject); })(); window.test(" hello from js "); }).catch((err) => { alert(err); }); } reader.readAsArrayBuffer(f); }, ()=>{alert("ERR2");} ); }, (err)=>{alert("ERR");} ); |
window.test(" hello from js ");
でwasm側の関数が呼ばれます。
確認用にcallback関数も用意しておきます。
1 2 3 |
window.textCallback = (v)=>{ alert(v); } |
wasm内の関数が呼び出され、コールバックでalertが実行されます。
React→Cordova
Reactでアクセスしたファイルは上の時点では存在しません。
ビルドしたソース一覧にwasmファイルを追加する必要があります。
今回の例だとwww/staticにmediaというフォルダを作成してそこにtest.wasmを置いています。
単体で使うならreactのpublic内に配置するとビルド時にwww直下に配置されるので、それを読み込むようにしてもいいかもしれません。
エラーリスト
CompileError: AsyncCompile: Wasm decoding failed: expected xxx
誤ったファイル読み込み方法(File形式のままやBinaryStringで読み込んだ)でコンパイルエラーになりました。
RangeError: WebAssembly Instantiation: Out of memory: wasm memory
テスト用端末(CP-L45s/Andorid6)で発生してました。
色々調べても原因がわからず予備端末(P9 lite)で実行してみたら発生しませんでした。どちらもRAM2Gなのでメモリ不足かどうかよくわからない。
原因を探っているとGOのビルドに問題がありそう。
wamsというツールを使ってメモリ量を減らすとOut Of Memoryは出なくなったけど関数が呼び出せませんでした(P9 liteでは依然問題なく動く)。
所感
問題はまだ残ってますがとりあえず動かすことはできそうだとわかりました。
色々試してみて実用が可能そうなら本格的に使ってみたいです。