1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Go言語でWebAssemblyを実装

Last updated at Posted at 2022-03-19

簡単なWebAssemblyを実装

モジュールディレクトリの作成とgo.modを生成します。

mkdir wasm
cd wasm
go mod init example.com/wasm

main.goを作成します。

package main

import "fmt"

func main() {
	fmt.Println("Hello, WebAssembly!")
}

Go言語のビルドコマンドに環境変数GOOS = jsGOARCH = wasmを設定して、main.goをWebAssembly用にコンパイルしてmain.wasmを生成します。

GOOS = js GOARCH = wasm go build -o main.wasm

main.wasmだけでは動かないので、wasm_exec.js(JavaScriptサポートファイル)をコピーします。

cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

wasm_exec.jsを使ってmain.wasmを実行するindex.htmlを作成します。

<html>
	<head>
		<meta charset="utf-8"/>
		<script src="wasm_exec.js"></script>
		<script>
			const go = new Go();
			WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
				go.run(result.instance);
			});
		</script>
	</head>
	<body></body>
</html>

あとは、WebサーバーのDocumentRootにindex.htmlmain.wasmwasm_exec.jsを配置してブラウザでアクセスすれば、コンソール(開発ツール)に「Hello, WebAssembly!」の文字列が表示されます。

DocumentRoot
├── index.html
├── main.wasm
└── wasm_exec.js

Go言語でJavaScriptを制御する

このままだとmain.wasmが実行後すぐに終了してしまい、JavaScriptのイベントを受け取れません。そこでチャンネルを生成して、チャンネルを受信するまでmain関数をブロックするようにします。

func main(){
	done := make(chan int)

	// 処理

	<-done
}

JavaScriptを制御するためのsyscall/jsモジュールをimportします。

import "syscall/js"

syscall/jsのパッケージを使えば、JavaScriptをGo言語から制御することも、JavaScriptからGo言語を実行することも可能です。

JavaScriptからGo言語を実行するためのJavaScriptの関数をGo言語で定義する

var goFunc js.Func
defer goFunc.Release()
goFunc = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
	arg1 := args[0]
	log.Printf("arg1=%v", arg1) // ブラウザのコンソールに出力
	return nil
})
js.Global().Set("goFunc", goFunc)

Go言語からJavaScriptのjsFunc関数を実行する

js.Global().Get("jsFunc").Invoke(arg1)

※ wasmを実行しているHtmlにjsFunc関数が定義されている必要があります。

JavaScriptのEventListenerにGo言語で定義したJavaScriptの関数を登録する

var onChangeMyText js.Func
defer onChangeMyText.Release()
onChangeMyText = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
	event := args[0]                                   // eventオブジェクト
	myText = event.Get("target").Get("value").String() // event.terget.valueのJSコードと同等
	return nil
})
js.Global().
	Get("document").
	Call("getElementById", "myText").
	Call("addEventListener", "change", onChangeMyText)

beforeunloadmイベントにmainを止めているチャンネルにメッセージを送るメソッドを登録する

var onBeforeunload js.Func
defer onBeforeunload.Release()
onBeforeunload = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
	done <- 1 // チャンネルに値を送信してアプリを終了する
	return nil
})
js.Global().
	Call("addEventListener", "beforeunload", onBeforeunload)
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?