github pages でWASMを使ったGoのWebツールを動かす【その2】(WebAssembly導入)
ページの構成
- github pages でWASMを使ったGoのWebツールを動かす【その1】(github pages導入) - ludwig125のブログ
- github pages でWASMを使ったGoのWebツールを動かす【その2】(WebAssembly導入) - ludwig125のブログ
- github pages でWASMを使ったGoのWebツールを動かす【その3】(WebAssemblyでの計算機) - ludwig125のブログ
- github pages でWASMを使ったGoのWebツールを動かす 【その4】(WebAssemblyでのUnixTime変換ツール作成) - ludwig125のブログ
- github pages でWASMを使ったGoのWebツールを動かす 【その5】(UnixTime変換ツールのTinyGoへの置き換え) - ludwig125のブログ
- github pages でWASMを使ったGoのWebツールを動かす 【その6】(WASM の Web ツールを github pages で公開する) - ludwig125のブログ
WebAssembly
以下では、WebAssembly を使った Web ページの作成方法を確認します。 この後で、github pages 上で、Go Wasm のページを公開することが目的です。
公式の説明
WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications.
WebAssembly(略称:Wasm)は、stack-baseの仮想マシン用のバイナリ命令形式です。 Wasmは、プログラミング言語用のポータブルなコンパイルターゲットとして設計されており、クライアントおよびサーバーアプリケーションのWeb上でのdeployを可能にします。
The Wasm stack machine is designed to be encoded in a size- and load-time-efficient binary format. WebAssembly aims to execute at native speed by taking advantage of common hardware capabilities available on a wide range of platforms.
Wasmスタックマシンは、サイズとロード時間の効率的なバイナリ形式でエンコードされるように設計されています。 WebAssemblyは、幅広いプラットフォームで利用可能な一般的なハードウェア機能を活用することで、ネイティブスピードで実行することを目指しています。
補足説明
WebAssembly を使用すると、JavaScript と同じように Rust、C、Go などの言語で Web ツールを作成できます。これにより、既存のライブラリを移植したり、JavaScript で利用できない機能を活用したりできます。
また、WebAssembly はバイナリ形式にコンパイルされるためコードの高速実行が可能になります。 JavaScript より速度を上回ることを目標にしているらしいです。 Go でも、Go1.11 から標準の機能として Go のコードを WebAssembly にコンパイルする機能が追加されました。
今の自分の Go のバージョンは以下の通りでした。
[~/go/src/github.com/ludwig125/githubpages] $go version go version go1.17 linux/amd64
Go WebAssembly
https://github.com/golang/go/wiki/WebAssembly#getting-started
を参考に進めます。
Getting Started
まずは簡単なプログラムを作成します。
main.go
package main import "fmt" func main() { fmt.Println("Hello, WebAssembly!") }
このコードを WebAssembly 形式で、build するには以下のようにします。
Go にはクロスコンパイルという機能で、別のアーキテクチャや別の OS 向けのバイナリをビルドすることができます。
ここでは、 GOOS
をjs
に、GOARCH
を wasm
にすることで、wasm 用のファイルにしています。
また、-o
でmain.wasm
を指定したので、この名前の実行可能な WebAssembly ファイルが作られることになります。
$ GOOS=js GOARCH=wasm go build -o main.wasm
この main.wasm
をブラウザ上で実行するために、Javascript と HTML が必要になります。
Go の最近のバージョンにはデフォルトで wasm 用の javascript(js)が同封されているので、それを以下のように手元に持ってきます。
$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
また、以下の通り、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>
上のコードで重要なのは以下の2つです
<script src="wasm_exec.js"></script>
WebAssembly.instantiateStreaming
- これは Javascript API で、wasm ファイルの読み込みを可能にします
https://github.com/golang/go/wiki/WebAssembly#getting-started
には、ブラウザがWebAssembly.instantiateStreaming
に対応していない場合は polyfill
を使うようにと書かれていますが、私の環境では普通に実行できたのでここではこのまま使用しました。
polyfill
この辺の WASM を使う場合の説明は以下が詳しいです
ここまでの段階で以下のファイルが存在します。
[~/go/src/github.com/ludwig125/githubpages] $ls index.html main.go main.wasm* wasm_exec.js
これを Web サーバ上で実行するために、 goexec
を使います。
もちろん、別途 Go でサーバプログラムを作ってもいいです( 例:https://go.dev/play/p/pZ1f5pICVbV )が、ここでは公式ドキュメントに従って以下のように goexec でサーバを立てます。
goexec の install(初回のみ)
$ go get -u github.com/shurcooL/goexec
goexec でサーバ起動(ここでは Port 8080 でサーバを立ち上げています)
$ goexec 'http.ListenAndServe(`:8080`, http.FileServer(http.Dir(`.`)))'
注意:うまく動かないときは以下の通り Go の環境設定をする必要があります
また、goexec 実行時に以下のようなエラーが出た場合は、すでに同じ Port で goexec を起動していてバッティングしている可能性があります
(*net.OpError)(&net.OpError{ Op: (string)("listen"), Net: (string)("tcp"), Source: (net.Addr)(nil), Addr: (*net.TCPAddr)(&net.TCPAddr{ IP: (net.IP)(nil), Port: (int)(8080), Zone: (string)(""), }), Err: (*os.SyscallError)(&os.SyscallError{ Syscall: (string)("bind"), Err: (syscall.Errno)(0x62), }), })
サーバ起動した状態でブラウザでhttp://localhost:8080/
にアクセスします。
ちなみに、公式ドキュメントにはhttp://localhost:8080/index.html
となっていますが、普通の Web サーバでは http://localhost:8080/
のようにスラッシュで終わる URL にアクセスすると自動でindex.html
を探すようになっているので同じことです。
この Web ページ上で、JavaScript のデバッグコンソールを開きます。
Chrome では、F12
で開けます。
go wasm を github pages で動かす
2021/12/30 の時点で、github pages で Web ページを公開する方法は3通りしかないようです
- master ブランチ
- master ブランチ上の
docs/
フォルダ gh-pages ブランチ
github リポジトリでは今後master
ではなくmain
ブランチがデフォルトになったので、今回はmain
ブランチのdocs/
以下に wasm ファイルをおいてみます。
[~/go/src/github.com/ludwig125/githubpages] $ls docs index.html main.go main.wasm* wasm_exec.js
これで、以下の通り、main
ブランチのdocs/
を選んでSave
します。
30 秒ほど待つと、
https://ludwig125.github.io/githubpages/
に更新が反映されて以下の通り、go wasm の結果が見られるようになりました。
これで、githubpages で Go の wasm の Web ページを公開することができるようになりました。
以降、main ブランチを修正すれば、この Web ページも更新されるはずです。
毎回反映を待つのが嫌だったり、ローカルで確認したい場合はgoexec
を使えばいいわけです。