Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
GopherJS+Vecty
Search
irieda
February 24, 2018
Technology
1.1k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
GopherJS+Vecty
Goだけでつくるフロントエンド入門
irieda
February 24, 2018
More Decks by irieda
See All by irieda
SpaGoでSPAを作ろう!
nobonobo
0
660
TinyGoでIoTを始めよう
nobonobo
2
930
Goだけでロビーサーバーを作ってみた
nobonobo
2
580
Other Decks in Technology
See All in Technology
AI ネイティブな組織に Gemini Enterprise Agent Platform がなぜ必要なのか
asei
1
190
オートロックマンションなのに、各部屋は施錠なし!? 攻撃者が組織内ネットワークで大暴れする理由 / The Front Door Is Locked, but the Rooms Are Wide Open: Why Attackers Move Freely Inside Enterprise Networks
nttcom
1
1.6k
20260807_第6回_関東kaggler会LT_claw系bot xangiと始める、"寂しくない" kaggle
sugupoko
0
180
SnowflakeCoCoでデータエンジニアリング!
foursue
0
180
Goでデータパイプラインを作ろう
sansantech
PRO
0
340
今こそ聞きたいソフトウェア設計 ドメイン駆動設計再入門
masuda220
PRO
17
6.4k
AIが自社のTableauを操作する世界へ:Tableau MCP超入門
tbtykk
0
120
もう一度考える SRE チームの作り方・育て方 / Rethinking SRE #1: Building and Growing SRE Teams
rrreeeyyy
6
1k
【CEDEC2026】『GRANBLUE FANTASY: Relink - Endless Ragnarok』のバトル制作事例 ~最高のキャラゲーを目指して~
cygames
PRO
0
220
AIコーディングの次。コードレビューと理解負荷を解消して組織の開発生産性を高める
moongift
PRO
2
2.2k
OSPN.JPバージョンアップ作業進捗のご報告 / 20260801-osc26kyoto
akkiesoft
0
350
JavaScript 研修 (2026)
recruitengineers
PRO
1
440
Featured
See All Featured
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
GraphQLとの向き合い方2022年版
quramy
50
15k
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
430
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
230
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
470
Google's AI Overviews - The New Search
badams
0
1.1k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.4k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.5k
Transcript
Go だけで作る Go だけで作る フロントエンド入門 フロントエンド入門
お前誰よ? お前誰よ? メカトロソフト屋 Pythonista -> Gopher なんでも Go で書いちゃうひと Go
歴は 5 年目 サイト: 会社: 144Lab(2017/07/01 から新社名) HN: @nobonobo http://golang.rdy.jp/
リッチなフロントエンド作りたい? リッチなフロントエンド作りたい? もちろん もちろん 作りたいですよね! 作りたいですよね!
でも・・・ でも・・・
JS を書きたく無いでござる JS を書きたく無いでござる
JS を書きたく無いでござる JS を書きたく無いでござる
絶対に JS を書きたく 絶対に JS を書きたく 無いでござる 無いでござる ( 個人的な感想です)
( 個人的な感想です) そこで そこで
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
関連ライブラリ 関連ライブラリ トランスパイラ: 仮想 DOM: ルーター: Bootstrap4コンポーネントセット: GopherJS(BSD) Vecty(BSD) github.com/go-humble/router(MIT)
github.com/nobonobo/bootstrap4(MIT)
GopherJS の近況 GopherJS の近況 速度より安定性を重視 出力ターゲットは ES5 ES2015~ES2017 の新記述の最適化がない Go1.10
サポートが着々と進んでる (Go 本体では WebAssembly 実装の実験も!!)
Vecty の近況 Vecty の近況 鋭意安定板に向けて改善真っ只中 昨年中に 5~6 回の破壊的変更がありました 破壊的変更の予定がまだ少しあります 本格利用はしばしお待ちを
HTML/CSS/JS の全てを Go で書ける というわりに CSS 支援は弱い
Vecty の提供機能 Vecty の提供機能 HTML ビルダ レンダラー コンポーネント プロパティ ほんとこれだけ。
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>
レンダラー レンダラー コンポーネントのレンダリングは二種類ある RenderBody: 初期レンダリング Rerender: 差分レンダリング
コンポーネント コンポーネント Core 実装と Render メソッドを持つ プロパティを元に HTML を生成する実装 コンポーネントツリーが仮想
DOM 相当 type MyComponent struct { vecty.Core } func (c *MyComponent) Render() vecty.ComponentOrHTML { return elem.Header1(vecty.Text("Hello!")) }
プロパティ プロパティ コンポーネント定義のフィールド 任意の型に`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)) }
ミニマムな例 ミニマムな例
ミニマムな実装例 ミニマムな実装例 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) }
ミニマムな実行例 ミニマムな実行例 Top click
プロパティな例 プロパティな例
プロパティな実装例 プロパティな実装例 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) })
プロパティな実行例 プロパティな実行例 Top click
Vecty の不足機能 Vecty の不足機能 ルーター/ビュー スタイルシート Flux 相当
ルーター/ ビュー ルーター/ ビュー いくつか試したところ これが Vecty 用でもないけど 使いやすかった。 github.com/go-humble/router(MIT)
スタイルシート スタイルシート 個別のスタイル操作はできる スタイルシートに対する支援がまだない CSS は頑張って用意するしかなさそう
Flux 相当 Flux 相当 サンプルが採用している方法を参考に。 アクション: メッセージ定義 ディスパッチ: メッセージのディスパッチャ モデル:
アプリのデータモデル定義 ストア: アプリ全体のデータストア ビュー: 最上位コンポーネント(概念を追加) ハンドラー: 振る舞い実装(概念を追加)
1 方向に回す 1 方向に回す
アクション アクション 1 アクションに 1 振る舞い 振る舞い予約の抽象的概念 振る舞いに渡すパラメータ定義
ディスパッチ ディスパッチ アクションの送信と受信を繋ぐ 送信側と受信側を疎結合にする 定型処理
モデル モデル アプリで保有するデータ構造定義 概ね JSON タグをつけて運用 バックエンドと共通で利用できる
ストア ストア モデル定義に沿ったデータを保持 ロードされる JS と同じライフサイクル アプリ要件で永続化と復元機能が必要 ぶっちゃけただのグローバル変数 API 結果のキャッシュのようなもの
GopherJS はシングルスレッド動作のみなので 基本は排他処理等は気にしない
ビュー ビュー コンポーネントの性質 HTML の組み合わせを抽象化 プロパティを持ち、それを元に描画を決定 DOM イベントをアクションに翻訳する ビューの性質 Body
を根とするコンポーネントツリー ルーターで URL と 1 対 1 に対応
ハンドラー ハンドラー アクションに対応する挙動実装群 ストアを書き換えしてもいい唯一の存在 サンプルではストアパッケージに書いてる
ルーターの例 ルーターの例
ルーターの実装例 ルーターの実装例 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(
ルーターの実行例 ルーターの実行例 top link:next1 click
中規模な実装例 中規模な実装例 Bootstrap4 と API 呼び出し
フォルダ構成 assets/ スタティックファイル群 models.go データスキーマ components.go コンポーネント定義群 views.go ビュー定義群 main.go
メイン実装
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
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
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"))
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
中規模な動作例 中規模な動作例 Users Posts Leanne Graham
[email protected]
Ervin Howell
[email protected]
Clementine Bauch
[email protected]
Patricia Lebsack
[email protected]
Chelsey Dietrich
[email protected]
Mrs. Dennis Schulist
[email protected]
Kurtis Weissnat
[email protected]
Nicholas Runolfsdottir V
[email protected]
QR コードコンポーネント QR コードコンポーネント
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 {
QR コード動作例 QR コード動作例 QR Code Text: WIFI:S:<SSID>; T:<WPA|WEP|>; P:<password>;;
スゴイところ スゴイところ JS の QR ライブラリつかってない。 JS を意識していない Go のライブラリを
GopherJS から利用しているだけ。
GopherJS 開発ツール GopherJS 開発ツール 「gopherjs serve <パッケージパス>」が基本 あとは Go ソースを書き換えた状態で
「 」にアクセスするだけで 再構築した js がサーブされます。 index.html があればそれをサーブします。 存在しない場合はミニマムなものがサーブされます。 http://localhost:8080
デバッグ デバッグ もちろんデバッグもできます。 Go のソースコードで!
ビルド ビルド 「-m」にてミニファイした結果が出力されます。 $ gopherjs build -m -o app.js .
チャットアプリの実際 チャットアプリの実際 https://github.com/nobonobo/vecty-sample
<リポジトリルート> app/ フロントパッケージルート backend/ バックエンドルート main.go サーバー起動実装
開発時のサーバー 開発時のサーバー 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) } }
<フロントパッケージルート> vendor/ その他の Go 依存パッケージ actions/ アクション定義群 assets/ 静的ファイル群 components/
コンポーネントセット dispather/ ディスパッチャ実装 models/ アプリモデル定義群 store/ アプリストレージ実装 router/ ルーター実装 views/ アプリ向けビューセット main.go メイン実装 index.html アプリ HTML
チャットアプリ動作例 チャットアプリ動作例 Top dead‑simple chap app Create New Room
パッケージが分かれてると パッケージが分かれてると 追加するモデルやストア 追加するアクション 追加する静的ファイル 追加するコンポーネント 追加するビュー 追加先に迷わなくて済みます。
パッケージ間依存 パッケージ間依存 store -> models actions -> models, store components
-> models, dispatcher views -> store, components 振る舞いと見た目とアプリデータが 疎結合
フロントのデプロイ フロントのデプロイ 以下のファイル群を静的にサーブ assets/ index.html app.js 内容 必要 追加 <html>
<head> <meta charset="utf-8"> <script src="app.js"></script> </head> <body> </body> </html>
ロード時間の解決案(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>
ロード時間の解決案(2) ロード時間の解決案(2) 先日公開されたサービス GopherJS パッケージを CDN キャッシュ jsgo.io https://github.com/dave/jsgo
Vecty の Pros/Cons Vecty の Pros/Cons
Pros Pros 基本の知識は HTML/CSS/Go のみで OK API やモデル定義をクラサバで共有できる 成果物は ES5
相当で polyfill 不要 豊富な PureGo のライブラリが利用可能 型のある開発は素晴らしい Vecty 本体は small & clear なので読みやすい
Cons Cons 結局 DOM まわりの知識は必要 DOM まわりを Go で置き換えるのに慣れが必要 JS
の既存 lib 使うならやっぱり JS 知識が必要 成果物 JS のファイルサイズがやや大きめ 開発中でもパッキングするのでリロード重い コンポーネントの設計はやはり難しい Vecty 安定板までに破壊的変更の予定がある
まとめ まとめ
とにかくビルドが早い とにかくビルドが早い 型チェック トランスパイル ミニファイ パック 上記処理のほとんどを1度のパースで行う。
JS の Isomorphic 開発 JS の Isomorphic 開発 nodejs/yarn webpack/esm/babel
eslint/prettier/flowtype mocha/react か vue.js etc... それぞれ要素技術ごとに薄い本ができるツ それぞれ要素技術ごとに薄い本ができるツ ラミ ラミ
Go の Isomorphic 開発 Go の Isomorphic 開発 go: 依存/整形/型検査/Lint/テスト/バックエンド
gopherjs: 開発サーバー/ES5/ミニファイ/パック vecty: 仮想 DOM フレームワーク たったこれだけで始められる たったこれだけで始められる Go に慣れた人が新たに覚える事は非常に少ない Go に慣れた人が新たに覚える事は非常に少ない
いろんな資産が使える いろんな資産が使える PureGo の資産はそのまま GopherJS に JS の資産はラップすれば GopherJS に
GopherJS の資産は GopherJS に GopherJS は GopherJS はジャイアニズム ジャイアニズム
しなくていいこと しなくていいこと 毎年追加される言語仕様を追う モジュール機構の選択 依存ツールメジャーバージョンアップ追従 コード整形ツールの調整 ツール間の競合機能の調整 バージョンの不整合の調整
GopherJS+Vecty GopherJS+Vecty おすすめです おすすめです
応用 1 応用 1 面白そう pouchdb(js)/couchdb(ネイティブ)両対応 pouchdb 使うとオフライン動作し、 オンライン化した時にクラウド上の couchdb
に同期なんてことができる。 Firebase(mBaaS)のような環境を作れるかも? だれかやってみて! だれかやってみて! kivik(isomorphic)
応用 2 応用 2 gRPC サーバーをバックエンドにできる。 クラサバ結合部の設計は gRPC の IDL
で完結する。 だれかやってみて! だれかやってみて! gopherjs-grpc-websocket
質問? 質問?
おしまい おしまい