Wecty: フロントエンドツールキット for Go and TinyGo
go get github.com/nobonobo/wecty/cmd/wecty
top.html
<form @submit="{{c.OnSubmit}}">
<button>Submit</button>
</form>
以下のコマンドを実行した場合、
wecty generate -c TopView top.html
top_gen.go が生成されます
package main
import (
"github.com/nobonobo/wecty"
)
func (c *TopView) Render() wecty.HTML {
return wecty.Tag("form",
wecty.Event("submit", c.OnSubmit),
wecty.Tag("button", vecty.Text("Submit")),
)
}
以下のような Go コードを手書きで書いておくことでコンポーネントとして利用可能になります。
top.go
package main
import (
"github.com/nobonobo/wecty"
)
type TopView struct {
wecty.Core
}
func (c *TopView) OnSubmit(ev js.Value) interface{} {
println("submit!")
return nil
}
また以下の記述を top.go に加えておくと go generate で wecty generate が自動的に走るようになります。
//go:generate wecty generate -c TopView -p main top.html
main.go
package main
import (
"github.com/nobonobo/wecty"
)
func main() {
wecty.RenderBody(wecty.Tag("body", &TopView{}))
select {}
}
あとはwecty server
を起動しておけば、
http://localhost:8080をブラウザで開くだけで
top_gen.go が生成され WASM がビルド&サーブされブラウザで動作を開始する
Q: なぜ Vecty とは別に作ったの?
A: GopherJS の開発が停滞しつつあること、Vecty は GopherJS と Go 両対応により複雑な実装になっている。
Q: Router はなぜハッシュベース?
A: URL を書き換えるスタイルはプロキシサーバーの URL 割り当てと整合をとる必要がある。ハッシュベースは単一の URL を振り向けるだけで動作する。つまり、SPA コンテンツを S3 に置いた場合でも動作する。
Q: Vecty のように prop や event パッケージを設けないのはなぜ?
A: 基本のマークアップは wecty generate の出力に任せるのでマークアップの容易さは無用だった。それにそれらのパッケージが WASM サイズの肥大化を招いていた。
Q: wecty generate のマークアップ機能が足りないのはなぜ?
A: 頑張っても Go の手書きの自由度を超えることはできない。ユーザーは wecty generate で済ますか Go のコードで細かく書いてコンポーネントを実装するかを使い分けてもらいたい。
Q: コンポーネントより細かい単位の最適な DOM ツリーの更新をしないのはなぜ?
A: 軽量な実装で仮装 DOM を実装した。賢くすることで描画更新は早くなるかもしれないが、WASM サイズが膨れてしまうことは避けたかった。速度を極力落とさない作りはユーザーがチャレンジできる。それはコンポーネントの粒度を小さく保つこと。
Render() wecty.HTML
メソッドを持つことコンポーネント.Render() HTML
メソッドを実装するには
単一の wecty.Tag(...)の戻り値を return するように記述する。
func (c *コンポーネント) Render() HTML {
return wecty.Tag(...)
}
wecty.Tag 関数の定義は以下の通り
wecty.Tag(tagName, markups ...wecty.Markup) *Node
tagName には HTML タグ名を渡す。markups には以下の記述を書く。
Markup になれるもの一覧
wecty いくつかのサブコマンドをもつユーティリティ
Usage of generate:
-c string
component name
-o string
output filename
-p string
output package name (default "main")
output filename
=basename_gen.go
package name
=main
component name
<body></body>
-> wecty.Tag("body")
<h1 id="title">Title</h1>
:
wecty.Tag("h1",
wecty.Attr("id", "title"),
vecty.Text("Title"),
)
<h1 class="title large">Title</h1>
:
wecty.Tag("h1",
wecty.Class{
"title": true,
"large": true,
},
vecty.Text("Title"),
)
<form @submit="{{c.OnSubmit}}">
<button>Submit</button>
</form>
wecty.Tag("form",
wecty.Event("submit", c.OnSubmit),
wecty.Tag("button", vecty.Text("Submit")),
)
<import>github.com/nobonobo/examples/todo/components</import>
<div><raw>&components.Item{}</raw></div>
import (
"github.com/nobonobo/examples/todo/components"
)
...
return wecty.Tag("div",
&components.Item{},
)
...
開発用簡易 HTTP サーバー
Usage of server:
-addr string
listen address (default ":8080")
-p path=endpoint
add reverse proxy rule (allow multiple rules)
-tinygo
use tinygo tool chain
例:
wecty server -addr :8080 -p /api/=http://localhost:9001
バックエンドサーバーを http://localhost:9001 にて動作させた状態で開発を進める場合などで使います。
Todo サンプルのコンパイル事例
ツール | WASM サイズ | gzipped |
---|---|---|
Go | 2.8MiB | 787.2KiB |
TinyGo | 374KiB | 154KiB |