1. ホーム
  2. スクリプト・コラム
  3. ゴラン

golang言語でのwasm環境構築の流れを詳しく説明します

2022-01-07 11:29:10

golangのインストール

によるgolangのインストール 公式アドレス MacOSは、以下の方法でダウンロードすることもできます。 brew クイックインストール

$ brew install golang

$ go version
go version go1.17.2 darwin/arm64


golang環境のテスト

新しいファイルmain.goを作成し、書き込みます。

package main

import "fmt"

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


go run main.goを実行すると、出力されます。

$ go run main.go
Hello World!

GO MODULESが有効な場合、go mode initを使用してモジュールを初期化するか、GO111MODULE=autoに設定する必要があります。

golangをWASMとしてパッケージングする

通常、golangのパッケージには2つの方法があります。golangに付属している方法とtinygoを使用する方法です。コンパイルされたwasmモジュールがより小さくなるため、tinygoを使うことをお勧めします。

  • golangでネイティブにコンパイルする

wasm モジュールをコンパイルする前に、golang のクロスコンパイルパラメータ、ターゲットシステム GOOS=js とターゲットアーキテクチャ GOARCH=wasm を設定する必要があります:。

// macos
$ GOOS=js GOARCH=wasm go build -o main.wasm

// windows temporarily set golang environment parameters (only works on the current CMD)
$ set GOOS=js 
$ set GOARCH=wasm
$ go build -o main.wasm


  • tinygoでコンパイルする

公式ドキュメントに従って直接インストールするだけで、MacOSの場合は以下のようになります。

$ brew tap tinygo-org/tools
$ brew install tinygo

$ tinygo version
tinygo version 0.20.0 darwin/amd64 (using go version go1.17.2 and LLVM version 11.0.0)


以下のコマンドで再度main.goをパッケージ化します。

$ tinygo build -o main-tiny.wasm

  • パッケージファイルサイズ比較
$ du -sh . /*.wasm
228K . /main-tiny.wasm
1.9M . /main.wasm

ブラウザで実行する

ブラウザでmain.wasmを実行するには、まずJSのグルーコードが必要です。これはgolangがすでに提供してくれているので、直接コピーしてください。tinygoを使う場合とネイティブにコンパイルされたグルーコードを使う場合では、ケースバイケースで同等のものをコピーするという違いがあることに注意してください:。

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

// tinygo compile
$ cp "$(tinygo env TINYGOROOT)/targets/wasm_exec.js" . /wasm_exec_tiny.js


次に、HTMLの入力ファイルが必要です。index.htmlファイルを作成し、次のコードを記述してください。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src=". /wasm_exec_tiny.js"></script>
</head>
<body>
  <script>
    const go = new Go(); // definition in wasm_exec.js
    WebAssembly.instantiateStreaming(fetch('. /main-tiny.wasm'), go.importObject)
      .then(res => {
        go.run(res.instance); // execute the go main method
      });
  </script>
</body>
</html>

最後に、httpサーバーを起動し、実行させる〜。

// python
$ python3 -m http.server
$ python2 -m SimpleHTTPServer

// node
$ npm i -g http-server
$ hs

// gp
$ go get -u github.com/shurcooL/goexec
$ goexec 'http.ListenAndServe(`:8080`, http.FileServer(http.Dir(`. `)))'


例外ロギング

  • nodeのhttp-server経由でサービスを読み込むとエラーが発生する。
<ブロッククオート

> TypeError: WebAssembly' で 'compile' の実行に失敗しました。レスポンスの MIME タイプが正しくありません。

原因は、wasm ファイルのレスポンスヘッダの content-type が application/wasm; charset=utf-8 となっているためで、本来は application/wasm であるべきなのですが、そのようなことはありません。既知の回避策は、HTML で wasm を初期化する方法を次のように変更することです。

fetch('. /main-tiny.wasm')
  .then(res => res.arrayBuffer())
  .then(buffer => {
    WebAssembly.install(buffer, go.importObject)
      .then(res => {
        go.run(res.instance);
      })
  })


golang言語におけるwasm環境についての記事は以上です。golangにおけるwasm環境については、Script Houseの過去の記事を検索するか、以下の記事を引き続き閲覧してください。