golangでVuguを試してみた。

最近、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
```

```main_wasm.go　一部抜粋
 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```を書く

```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```のソースをみてみる。

``` github.com/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自体まだ触り始めたばかりなのでもっと面白いことができるようになりたい。

## ソースコード

https://github.com/shorii/vugu-demo