Share
Embed
GoのWebAssembly活用パターン紹介
Go Connect #7 (https://gotalk.connpass.com/event/355423/) の発表資料です
syumai
June 11, 2025
Transcript
32 slides
-
自己紹介 syumai ECMAScript 仕様輪読会 / Asakusa.go 主催 株式会社ベースマキナで管理画面のSaaS を開発中 Go
でGraphQL サーバー (gqlgen) や TypeScript でフロント エンドを書いています Software Design 2023 年12 月号から2025 年2 月号まで Cloudflare Workers の連載をしました Twitter ( 現𝕏): @__syumai Website: https://syum.ai -
今日話すこと WebAssembly について Go のWebAssembly の特徴 Go のWebAssembly の現在のユースケース Go
のWebAssembly の将来のユースケース -
WebAssembly の特徴 ポータブル あらゆるところで動く ブラウザ JS ランタイム (Node.js, Deno, Cloudflare
Workers 等) 各言語向けライブラリ (Wasmtime, Wasmer 等) CLI ツール (Wasmtime, Wasmer 等) Docker (WasmEdge) 安全 サンドボックス化された環境内で実行 素の状態ではOS の機能を触れない -
WebAssembly 関連の重要な技術 WebAssembly System Interface 略称はWASI WebAssembly がシステム (OS 等)
とやりとりするためのインタフェース 例えば、以下のようなシステムへの機能呼び出しインタフェースを実装できる ファイルアクセス HTTP 通信 -
WebAssembly 関連の重要な技術 WebAssembly Component Model WASI 0.2 の一部 WebAssembly 製のコンポーネントが実装するインタフェース定義を自由に行える
インタフェース定義用の言語であるWIT (Wasm Interface Type) が追加 ファイルアクセス、HTTP 通信等のインタフェースもWIT で書かれるように プログラミング言語を跨いだ機能呼び出しが可能に -
WIT の例 wit/component.wit package docs:[email protected]; interface add { add: func(x:
u32, y: u32) -> u32; } world adder { export add; } Go - The WebAssembly Component Model より http://component-model.bytecodealliance.org/language-support/go.html -
Go のWebAssembly の特徴 ビルドが簡単 普段のビルドコマンドに GOOS=js GOARCH=wasm を付けるだけでビルド可能 CGO を使っていなければ大体どんな実装でもビルドが通る
バイナリサイズが大きい Go のランタイムのサイズ自体が大きいので、簡単に数MB のバイナリになる 一応TinyGo という道具も使える ( かなり小さくなる) ブラウザ用途では考慮が必要 -
ブラウザでの実行 Go で実装したロジックをブラウザ上のJavaScript から呼び出す Go の充実した標準ライブラリの機能をブラウザで活用可能 暗号関係のライブラリなど DOM 操作などのブラウザAPI の操作用途にはあまり向かない
JS のエコシステムに最適化されているため バイナリサイズが大きいので、トラフィックの多いサイトには向かない -
ブラウザでの実行パターン 1. syscall/js.Global() の利用 2. go:wasmexport の利用 3. TinyGo &
Wasm Component の利用 -
1. syscall/js.Global() の利用 以下のように js.Global().Set("compress", ...) とすると、JS 側からグローバル な compress
関数を呼べる // 受け取ったUint8Arrayをgzip圧縮して返す関数 var compressFunc = js.FuncOf(func(this js.Value, args []js.Value) any { /* 中略 */ r, _ := compressor.Compress(src) var buf bytes.Buffer io.Copy(&buf, r) ua := newUint8Array(buf.Len()) js.CopyBytesToJS(ua, buf.Bytes()) return ua }) func main() { js.Global().Set("compress", compressFunc) select {} } https://github.com/syumai/go-wasm-gzipper/blob/master/main.go -
2. go:wasmexport の利用 Go 1.24 でサポート http://go.dev/blog/wasmexport 以下のようにすると、export されたadd 関数をJS
側から呼べる シグニチャに使える型が限られている点が課題 main 関数の select {} のおまじないは不要になった package main //go:wasmexport add func add(x, y int32) int32 { return x + y } func main() {} https://github.com/syumai/til/blob/main/go/wasmexport/main.go -
3. TinyGo & Wasm Component の利用 WIT からGo 向けのインタフェースを生成、それを実装してビルドするとWasm Component
化できる Wasm Component はbytecodealliance/jco でTS/JS から利用可能になる 今のところ、TinyGo でしか使えない -
3. TinyGo & Wasm Component の利用 WIT の例 package calculator:[email protected];
interface calculator { add: func(a: f64, b: f64) -> f64; subtract: func(a: f64, b: f64) -> f64; /* ... */ } world calculator-world { include wasi:cli/[email protected]; export calculator; } https://github.com/syumai/go-wasm- playground/blob/master/components/calculator/wit/world.wit -
3. TinyGo & Wasm Component の利用 Go 側の実装例 func init()
{ calculator.Exports.Add = func(a, b float64) float64 { return a + b } calculator.Exports.Subtract = func(a, b float64) float64 { return a - b } /* ... */ } https://github.com/syumai/go-wasm- playground/blob/master/components/calculator/main.go -
3. TinyGo & Wasm Component の利用 TS からの利用例 import {
calculator } from '../js-output/calculator.js'; function main() { console.log(calculator.add(1, 2)); // 3 console.log(calculator.subtract(5, 4)); // 1 } https://github.com/syumai/go-wasm- playground/blob/master/components/calculator/src/sample.ts -
プラグイン機構の構築 Wasm がポータブルな実行可能バイナ リであることを活用 Go 製のコマンドに、後付けで機能を 追加する github.com/knqyf263/go-plugin が代 表例
図はknqyf263/go-plugin の README から引用 Plugin のインタフェースだけを Protobuf で記述し、その実装は 後から追加できる wazero などで自前構築も可能 -
CDN Edge での実行 JS / Wasm のみをサポートする、CDN のEdge Function での実行に利用
軽量なランタイムで動作するので、一般的なFaaS と比べてコストが低い傾向にある インフラコストを抑える目的での利用が可能 Fastly Compute はGo をサポートしている (Wasm ランタイム) Cloudflare Workers はgithub.com/syumai/workers などで利用可能 Fermyon のSpin も注目されつつある -
アプリケーション実行コンテナとしての利用 WASI (WIT) を通じてシステム連携ができるWasm をビルドできれば、Wasm バイナリ 単体をコンテナとして扱える可能性がある WasmEdge によって実証されつつある Docker
image のビルドが不要になって、 go build で出力したWasm をデプロイする だけで済む日がいつか来るかも… ?