GolangでWebAssembly入門してみた
はじめに
WebAssemblyそういえば全く触ったことなかったな〜ということで、入門してみることにしました。
WebAssemblyとは
WebAssemblyとは、スタックベースの仮想マシン用のバイナリ命令フォーマットです。
元々はWebブラウザ上で、JavaScriptでは速度が出せない処理を高速で実行するためのバイナリフォーマットとして開発されました。
現在では、Webブラウザ上だけではなく、それ以外の環境のユースケースでも採用されるケースもあるようです。
※WebAssemblyのユースケースの例はこちらを参照
WebAssembly入門
さらっとどんなものなのかを押さえたところで、早速簡単なサンプルを使って、WebAssemblyを動かしてみたいと思います。
作るもの
MarkdownのEditorを作ります。
WebAssembly側でMarkdownのテキストをHTMLに変換する処理を用意し、それをブラウザから呼び出して使う形で作ります。
環境
- Golang 1.20.2
MarkdownをHTMLに変換する処理を作る
GolangでまずMarkdownをHTMLに変換する処理をWebAssemblyとして作ります。
まず、エントリーポイントとなるmain.go
を書きます。
package main
import (
"syscall/js"
"to-markdown/markdown"
)
func MarkdownToHtml(_ js.Value, args []js.Value) any {
// Markdown文字列を入力値として受け取り、
// HTMLに変換して返す
in := args[0].String()
out := markdown.ToHtml(in)
return out
}
func main() {
c := make(chan struct{}, 0)
// js.Global().Set()を実行することで、
// JavaScript側からGoの関数MarkdownToHtmlを
// markdownToHtmlという名前で呼び出せるように登録している
js.Global().Set("markdownToHtml", js.FuncOf(MarkdownToHtml))
<-c
}
次にHTMLに変換する処理を書きます。
package markdown
import (
"bytes"
"fmt"
"github.com/yuin/goldmark"
"strings"
)
func ToHtml(in string) string {
inBuf := []byte(in)
var outBuf bytes.Buffer
if err := goldmark.Convert(inBuf, &outBuf); err != nil {
fmt.Printf("fail to convert markdown: %v\n", err)
// 暫定仕様として、変換失敗時には元の文字列をそのまま返す仕様にする
return in
}
// 変換後の文字列には改行コードが含まれているので削除する
out := strings.ReplaceAll(outBuf.String(), "\n", "")
return out
}
これで必要な処理は実装できたので、実行用のバイナリを作成します。
次のコマンドで、Goのコードをビルドします。
GOOS=js GOARCH=wasm go build -o markdown-to-html.wasm
作ったMarkdown変換処理をJSから呼び出す
作ったwasmの処理を使用し、ブラウザでMarkdownのテキストをHTMLに変換する処理を作ります。
まず、wasm形式のファイルをブラウザに読み込むためのjsファイルをコピーします。jsファイルはローカルのGo環境を保存している場所にあり、次のコマンドでコピー可能です。
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
次にWebのエントリーポイントとなるindex.html
を作ります。
<html>
<head>
<meta charset="utf-8">
<title>Go WebAssembly</title>
</head>
<body>
<h1>Go WebAssembly</h1>
<!-- wasmファイルを扱うために必要なjsファイルを読み込む -->
<script src="./wasm_exec.js"></script>
<script>
// markdown-to-html.wasmファイルをブラウザに読み込む
const go = new Go();
WebAssembly.instantiateStreaming(fetch("markdown-to-html.wasm"), go.importObject).then((result) => {
const module = result.module;
const instance = result.instance;
go.run(instance);
document.getElementById("convert-markdown").disabled = false;
});
// Markdown文字列をHTML文字列に変換する
function convert() {
const inputElement = document.getElementById('input');
const outputElement = document.getElementById('output');
const inputText = inputElement.value;
// wasmのmarkdownToHtmlを呼び出している
const outputText = markdownToHtml(inputText)
outputElement.innerHTML = outputText;
}
</script>
<div>
<textarea id="input" placeholder="Enter text" rows="5" cols="50"></textarea>
<button onClick="convert();" id="convert-markdown" disabled>Convert Markdown</button>
</div>
<div>
<p>Output:
</p>
<span id="output">
</span>
</div>
</body>
</html>
index.html
をローカルサーバーを起動して読み込みます。
手段はなんでも良いですが、VSCodeのLive Serverを使うのが最も手軽だと思います。
動作確認
Markdownのテキストを入力してボタンを押すと...
無事HTMLテキストが表示されました。やったぜ。
さいごに
あんまり細かいことはわかってないですが、使い方を練習できたので満足です。
Discussion