最近、golangでwebassemblyに触れてみたのでその延長でvuguを試してみた。
Vugu
公式:https://www.vugu.org/
webassemblyでReactやVue風にUIを書くことができるらしい。
バージョン
- go1.12.6
Make sure you have at least Go 1.12 installed
公式のGetting Startedを読んでみると少なくともgolangのバージョンは1.12である必要があるらしいので注意
お試し
Getting Startedをそのままなぞるのではつまらないので少し違った手順で試してみる。
構成
vugu-demo/
┣ root.vugu
┣ wasm_exec.js
┗ index.html
これだけ
手順
root.vugu
を書く
<div class="my-first-vugu-comp">
<button @click="data.Toggle()">Test</button>
<div vg-if="data.Show">I am here!</div>
</div>
<style>
.my-first-vugu-comp { background: #eee; }
</style>
<script type="application/x-go">
type RootData struct { Show bool }
func (data *RootData) Toggle() { data.Show = !data.Show }
</script>
vugugen
をビルド
$ pwd
/path/to/vugu-demo
$ git clone https://github.com/vugu/vugu.git
$ ls
index.html root.vugu vugu wasm_exec.js
$ cd ./vugu
$ go build cmd/vugugen/vugugen.go
root.vugu
からgoのソースを生成するためのコマンドがあるのでビルドする。
root.vugu
からgoのソースを生成
$ /path/to/vugu-demo/vugu/vugugen /path/to/vugu-demo
$ ls
go.mod index.html main_wasm.go root.go root.vugu vugu wasm_exec.js
18 rootInst, err := vugu.New(&Root{}, nil)
19 if err != nil {
20 log.Fatal(err)
21 }
22
23 env := vugu.NewJSEnv("#root_mount_parent", rootInst, vugu.RegisteredComponentTypes())
24 env.DebugWriter = os.Stdout
25
26 for ok := true; ok; ok = env.EventWait() {
27 err = env.Render()
28 if err != nil {
29 panic(err)
30 }
31 }
-
18行目:
root.go
で定義されているRootコンポーネントを生成する。 -
23行目:webassemblyでDOMをレンダリングするための環境を生成する。
id
がroot_mount_parent
の要素にRootコンポーネントを展開する。 -
26~30行目: レンダリングループ。イベントが発生するまで
env.EventWait()
でブロックし、イベントが発生したらenv.Render()
でレンダリング処理を行う。
wasmファイルのビルド
$ GOOS=js GOARCH=wasm go build -o ./main.wasm ./*.go
$ ls
go.mod go.sum index.html main.wasm main_wasm.go root.go root.vugu vugu wasm_exec.js
index.html
を書く
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <title>example</title>
5 </head>
6 <body>
7 <div id="root_mount_parent">
8 <div></div>
9 </div>
10 <script src="./wasm_exec.js"></script>
11 <script>
12 const go = new Go();
13 WebAssembly.instantiateStreaming(fetch("./main.wasm"), go.importObject).then((result) => {
14 go.run(result.instance);
15 });
16 </script>
17 </body>
18 </html>
- 7~9行目: Rootコンポーネントが展開されるポイント。
id="root_mount_parent"
が指定されている要素に必ず子要素が存在することに注意。
vugu/env-js.go
のソースをみてみる。
150 c := e.rootInst
151 mountParentEl := document.Call("querySelector", e.MountParent)
152 if !mountParentEl.Truthy() {
153 return fmt.Errorf("failed to find mount parent using query selector %q", e.MountParent)
154 }
155
156 vdom, css, err := c.Type.BuildVDOM(c.Data)
157 if err != nil {
158 return err
159 }
160 _, _ = vdom, css
161
162 // do basic setup and ensure we have a css style element and a root element, in that order
163 mountChild1 := mountParentEl.Get("firstElementChild")
querySelector
で id="root_mount_parent"
の要素を取得したあと、firstElementChild
で子要素の最初の要素を取得しようとしているため、展開するポイントに子要素が存在しない場合エラーを吐いてしまう。なぜこのようになっているのかわからないが、自分でhtmlを作成する場合は注意が必要。なお、公式のGetting Startedで使用しているsimplehttp
ではベースとなるhtmlを自動的に提供してくれていますのでsimplehttp
を使用する際には注意は不要です。
- 10行目:
wasm_exec.js
読み込み
wasm_exec.js
は $(go env GOROOT)/misc/wasm
内にあります。
- 11~16行目: 前行程でビルドしたwasmファイルを読み込み
デプロイ
github.ioで適当にデプロイしてみる。以下URL
https://shorii.github.io/vugu-demo/
感想
最初index.html
の展開ポイントに子要素が必要だということがわからなくてはまってしまった。やっぱりわからないことがあったらソースコードを読むことが重要ですね。
golang自体まだ触り始めたばかりなのでもっと面白いことができるようになりたい。
ソースコード