Gopherjsを使ってJavascript化して色々してきましたが、ブラウザでバイナリを動かす手段としてWebAssemblyがあります。
GO1.11から追加された機能で情報も多くないですが、無理にJSにして使うよりも軽く速くなるかもしれないので使ってみたいと思います。
windows10でやっていくので他環境だと環境変数などは適宜変える必要があります。
基本的な流れはWikiに従います。
https://github.com/golang/go/wiki/WebAssembly
まずは適当な場所に実行用のファイルをコピーして使います。
1 |
cp %GOROOT%/misc/wasm/* wasmtestfolder |
最新版をGITで確認できますが、バージョンが違うとブラウザ実行時にエラーになったりします。
https://github.com/golang/go/tree/master/misc/wasm
テスト用のプログラムを書いてWASMとしてビルドします。
1 2 3 4 5 |
package main import "fmt" func main() { fmt.Println("Hello, WebAssembly!") } |
1 |
env GOOS=js GOARCH=wasm go build -o test.wasm test.go |
goexecを使ってテスト用の簡易サーバーを立てます。
1 2 3 4 5 |
go get -u github.com/shurcooL/goexec //linux goexec 'http.ListenAndServe(":8080", http.FileServer(http.Dir(".")))' //windows goexec http.ListenAndServe(\":8080\",http.FileServer(http.Dir(\".\"))) |
windowsだと書き方が大分違うトラップ。
ローカルホスト(http://localhost:8080/wasm_exec.html)にアクセスしてRUN。
テストプログラムで書いた内容がコンソールに出力されました。
サーバーを起動しないとCORS(Cross-Origin Resource Sharing)の問題がありwasmを読み込めません。
URL scheme must be “http” or “https” for CORS request.
Firefoxであればhtmlと同じ階層であればアクセス可能ですが、そのまま使うとfileスキームで読み込むためResponseの情報が足りずにエラーになります。
TypeError: “Response has unsupported MIME type”
Responseを新しく作れば静的ファイルのまま読み込みができます。
1 2 3 4 5 6 7 8 |
let wasmfile; const request = new XMLHttpRequest(); request.responseType = "blob"; request.open("GET", `test.wasm`); request.addEventListener("load", (event) => { wasmfile = new Response(event.target.response,{"headers":{'Content-Type':'application/wasm'}}); }); request.send(); |
ヘッダ書き換えはrequest.overrideMimeType("application/wasm");
でもいいです。
Chromeで動くか確認したい場合には以下のような方法もあります。
-
--disable-web-security --user-data-dir
オプションを付けてChrome起動 - ウェブサーバにアップロード、CROS設定してURLで読み込む
- ファイルにして読み込む(
wasmfile = new Response(evt.target.files[0]);
)
関数を作成して使用する場合にはチャンネルを使用してロックします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//HTML <button onClick="test(`from html`);">Test</button> //GO func test(jsv []js.Value) { fmt.Println("TEST"+jsv[0].String()) } func setFuncs(){ js.Global().Set("test", js.NewCallback(test)) } func main(){ setFuncs() done := make(chan struct{}, 0) <-done } |
main関数をロックせず、終了した後にtestを呼び出すと以下のエラー。
Error: bad callback: Go program has already exited
GopherJSで少し慣れているけどちょっと癖がある。
またWebAssembly自体の情報が少なくてGOに関わるものだともっと少ない。
しかしGOで作ったものをブラウザで使えるなら出来ることも広がるので色々試してみる価値はありそうです。