Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GopherJS+Vecty

irieda
February 24, 2018

 GopherJS+Vecty

Goだけでつくるフロントエンド入門

irieda

February 24, 2018
Tweet

More Decks by irieda

Other Decks in Technology

Transcript

  1. お前誰よ? お前誰よ? メカトロソフト屋 Pythonista -> Gopher なんでも Go で書いちゃうひと Go

    歴は 5 年目 サイト: 会社: 144Lab(2017/07/01 から新社名) HN: @nobonobo http://golang.rdy.jp/
  2. Go から Javascript Go から Javascript もちろん、Go から Javascript への変換には

    ですね! 参考情報 Go を JS に 100% 変換できます Go を JS に 100% 変換できます GopherJS http://golang.rdy.jp/2015/10/15/gopherjs/ http://golang.rdy.jp/playgopherjs/#/1
  3. HTML ビルダ HTML ビルダ タグ定義を使って生成 属性は Markup でラップして記述 慣れるまで大変 elem.Body(

    // <body> elem.Heading1(vecty.Text("TITLE")), // <h1>TITLE</h1> elem.Anchor( // <a href="/page"> vecty.Markup(prop.Href("/page")), vecty.Text("link"), // link ), // </a> ) // </body>
  4. コンポーネント コンポーネント Core 実装と Render メソッドを持つ プロパティを元に HTML を生成する実装 コンポーネントツリーが仮想

    DOM 相当 type MyComponent struct { vecty.Core } func (c *MyComponent) Render() vecty.ComponentOrHTML { return elem.Header1(vecty.Text("Hello!")) }
  5. プロパティ プロパティ コンポーネント定義のフィールド 任意の型に`vecty: prop `タグをつける コンポーネントが保有・参照するデータ 親から受け取って参照しつつ HTML を組む

    type MyComponent struct { vecty.Core Title string `vecty:"prop"` } func (c *MyComponent) Render() vecty.ComponentOrHTML { return elem.Header1(vecty.Text(c.Title)) }
  6. ミニマムな実装例 ミニマムな実装例 type TopView struct {vecty.Core} func (c *TopView) Render()

    vecty.ComponentOrHTML { vecty.SetTitle("TopView") return elem.Body( elem.Heading1(vecty.Text("First")), elem.Button(vecty.Text("click")), ) } func main() { top := &TopView{} vecty.RenderBody(top) }
  7. プロパティな実装例 プロパティな実装例 type TopView struct { vecty.Core Heading string `vecty:"prop"`

    } func (c *TopView) Render() vecty.ComponentOrHTML { vecty.SetTitle("TopView") return elem.Body( elem.Heading1(vecty.Text(c.Heading)), elem.Button( vecty.Markup( event.Click(func(ev *vecty.Event) { now := time.Now().Format(time.RFC3339Nano) c.Heading = fmt.Sprintf("Top: %s", now) vecty.Rerender(c) })
  8. Flux 相当 Flux 相当 サンプルが採用している方法を参考に。 アクション: メッセージ定義 ディスパッチ: メッセージのディスパッチャ モデル:

    アプリのデータモデル定義 ストア: アプリ全体のデータストア ビュー: 最上位コンポーネント(概念を追加) ハンドラー: 振る舞い実装(概念を追加)
  9. ルーターの実装例 ルーターの実装例 type NormalView struct { vecty.Core Title string `vecty:"prop"`

    Next string `vecty:"prop"` } func (c *NormalView) Render() vecty.ComponentOrHTML { vecty.SetTitle(c.Title) return elem.Body( elem.Heading1(vecty.Text(c.Title)), elem.Anchor( vecty.Markup(prop.Href("#/"+c.Next)), vecty.Text("link:"+c.Next), ), elem.Button( vecty Markup(
  10. models.go:Post models.go:Post // Post https://jsonplaceholder.typicode.com/posts type Post struct { UserID

    int `json:"userId"` ID int `json:"id"` Title string `json:"title"` Body string `json:"body"` } type Posts []*Post
  11. components.go:Post components.go:Post type PostInfo struct { vecty.Core Post Post `vecty:"prop"`

    } func (c *PostInfo) Render() vecty.ComponentOrHTML { return elem.Div(vecty.Markup(vecty.Class("card")), elem.Div(vecty.Markup(vecty.Class("card-body")), elem.Heading5(vecty.Text(c.Post.Title)), elem.Paragraph(vecty.Text(c.Post.Body)), ), ) } type PostInfoList struct { vecty Core
  12. views.go:/posts views.go:/posts type PostsView struct { vecty.Core Posts Posts `vecty:"prop"`

    } func (c *PostsView) Render() vecty.ComponentOrHTML { vecty.SetTitle("Posts") return &Layout{ Children: vecty.List{ elem.UnorderedList( vecty.Markup( vecty.Class("nav"), vecty.Class("nav-tabs"), ), elem.ListItem( vecty Markup(vecty Class("nav-item"))
  13. main.go main.go const API = "https://jsonplaceholder.typicode.com" func getResource(url string, v

    interface{}) error { resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() return json.NewDecoder(resp.Body).Decode(&v) } func main() { vecty.AddStylesheet("assets/bootstrap.min.css") vecty.AddStylesheet("assets/app.css") r := router.New() r ForceHashURL = true
  14. QR コード実装例 QR コード実装例 package components import ( "bytes" "log"

    "github.com/gopherjs/vecty" "github.com/gopherjs/vecty/elem" "github.com/aaronarduino/goqrsvg" "github.com/ajstarks/svgo" "github.com/boombuler/barcode/qr" ) // QRCode ... type QRCode struct {
  15. GopherJS 開発ツール GopherJS 開発ツール 「gopherjs serve <パッケージパス>」が基本 あとは Go ソースを書き換えた状態で

    「 」にアクセスするだけで 再構築した js がサーブされます。 index.html があればそれをサーブします。 存在しない場合はミニマムなものがサーブされます。 http://localhost:8080
  16. 開発時のサーバー 開発時のサーバー gopherjs serve を別途起動しておく /api/をバックエンドハンドラにマップ その他を「gopherjs serve」にリバースプロキシ func main()

    { u, _ := url.Parse("http://localhost:8080") rp := httputil.NewSingleHostReverseProxy(u) http.Handle("/", rp) http.Handle("/api/", backend.New()) l, err := net.Listen("tcp", ":8888") if err != nil { log.Fatalln(err) } log.Println("listen:", l.Addr()) if err := http.Serve(l, nil); err != nil { log.Fatalln(err) } }
  17. <フロントパッケージルート> vendor/ その他の Go 依存パッケージ actions/ アクション定義群 assets/ 静的ファイル群 components/

    コンポーネントセット dispather/ ディスパッチャ実装 models/ アプリモデル定義群 store/ アプリストレージ実装 router/ ルーター実装 views/ アプリ向けビューセット main.go メイン実装 index.html アプリ HTML
  18. パッケージ間依存 パッケージ間依存 store -> models actions -> models, store components

    -> models, dispatcher views -> store, components 振る舞いと見た目とアプリデータが 疎結合
  19. ロード時間の解決案(1) ロード時間の解決案(1) スピナー表示のあとで async 付きで JS を読む。 <html> <head> <meta

    charset="utf-8"> <link href="assets/app.css" media="all" rel="stylesheet" /> </head> <body> <div class="loader">Loading...</div> </body> <script async src="app.js"></script> </html>
  20. Pros Pros 基本の知識は HTML/CSS/Go のみで OK API やモデル定義をクラサバで共有できる 成果物は ES5

    相当で polyfill 不要 豊富な PureGo のライブラリが利用可能 型のある開発は素晴らしい Vecty 本体は small & clear なので読みやすい
  21. Cons Cons 結局 DOM まわりの知識は必要 DOM まわりを Go で置き換えるのに慣れが必要 JS

    の既存 lib 使うならやっぱり JS 知識が必要 成果物 JS のファイルサイズがやや大きめ 開発中でもパッキングするのでリロード重い コンポーネントの設計はやはり難しい Vecty 安定板までに破壊的変更の予定がある
  22. JS の Isomorphic 開発 JS の Isomorphic 開発 nodejs/yarn webpack/esm/babel

    eslint/prettier/flowtype mocha/react か vue.js etc... それぞれ要素技術ごとに薄い本ができるツ それぞれ要素技術ごとに薄い本ができるツ ラミ ラミ
  23. Go の Isomorphic 開発 Go の Isomorphic 開発 go: 依存/整形/型検査/Lint/テスト/バックエンド

    gopherjs: 開発サーバー/ES5/ミニファイ/パック vecty: 仮想 DOM フレームワーク たったこれだけで始められる たったこれだけで始められる Go に慣れた人が新たに覚える事は非常に少ない Go に慣れた人が新たに覚える事は非常に少ない
  24. いろんな資産が使える いろんな資産が使える PureGo の資産はそのまま GopherJS に JS の資産はラップすれば GopherJS に

    GopherJS の資産は GopherJS に GopherJS は GopherJS はジャイアニズム ジャイアニズム
  25. 応用 1 応用 1 面白そう pouchdb(js)/couchdb(ネイティブ)両対応 pouchdb 使うとオフライン動作し、 オンライン化した時にクラウド上の couchdb

    に同期なんてことができる。 Firebase(mBaaS)のような環境を作れるかも? だれかやってみて! だれかやってみて! kivik(isomorphic)
  26. 応用 2 応用 2 gRPC サーバーをバックエンドにできる。 クラサバ結合部の設計は gRPC の IDL

    で完結する。 だれかやってみて! だれかやってみて! gopherjs-grpc-websocket