Slide 1

Slide 1 text

Go + WASM で始めるWeb Frontend 開発 Emscripten & WebAssembly night !! #6 2018/12/14 (Fri.) @__syumai

Slide 2

Slide 2 text

自己紹介 syumai Twitter: @__syumai Merpay, Inc. (Backend / Go) 前職ではFrontend やってました React Native Vue.js etc...

Slide 3

Slide 3 text

本日のお題 Go とWebAssembly でWeb Frontend の開発をする

Slide 4

Slide 4 text

Go とWebAssembly

Slide 5

Slide 5 text

Go 1.11 でWASM サポー トが追加 8 月末頃Go 1.11 がリリー スされる その際、Experimental な機能としてWASM サポー トが入る オプション付きでビルドするとWASM として吐き出される

Slide 6

Slide 6 text

WASM ビルド用のコマンド G O O S = j s G O A R C H = w a s m g o b u i l d - o m a i n . w a s m G O O S = j s , G O A R C H = w a s m を指定 G O O S , G O A R C H はマルチプラットフォー ム向けの書き出しオ プション

Slide 7

Slide 7 text

Go のWASM の実行 Go 本家制作の w a s m _ e x e c . j s をロー ドしてから実行 < s c r i p t s r c = " w a s m _ e x e c . j s " > < / s c r i p t > < s c r i p t > ( a s y n c ( ) = > { c o n s t g o = n e w G o ( ) ; c o n s t { i n s t a n c e } = a w a i t W e b A s s e m b l y . i n s t a n t i a t e S t r e a m i n g ( f e t c h ( " m a i n . w a s m " ) , g o . i m p o r t O b j e c t ) g o . r u n ( i n s t a n c e ) ; } ) ( ) ; < / s c r i p t >

Slide 8

Slide 8 text

Go からJavaScript を呼ぶ

Slide 9

Slide 9 text

syscall/js pacakge Go からJS の世界を触りに行くためのpackage https://golang.org/pkg/syscall/js/

Slide 10

Slide 10 text

syscall/js の基本的な使い方 / / w i n d o w を取ってくる w i n d o w : = j s . G l o b a l ( ) / / d o c u m e n t を取ってくる d o c u m e n t : = w i n d o w . G e t ( " d o c u m e n t " ) / / 任意のD O M を取ってくる b t n : = d o c u m e n t . C a l l ( " g e t E l e m e n t B y I d " , " b u t t o n " ) / / E v e n t L i s t e r n e r を設定する b t n . C a l l ( " a d d E v e n t L i s t e n e r " , " c l i c k " , j s . N e w C a l l b a c k ( f u n c ( [ ] j s . V a l u e ) { p r i n t l n ( " H e l l o , w o r l d ! " ) } ) , )

Slide 11

Slide 11 text

使い方の基本的なルー ル JS の世界の値は、 j s . V a l u e 型で渡ってくる! ( 具象型です) 値がObject であれば、 o b j . G e t ( " k e y " ) , o b j . S e t ( " k e y " , " v a l u e " ) が使える global なObject は、 j s . G l o b a l ( ) で取れる

Slide 12

Slide 12 text

Go の値をJS の値として渡す js.ValueOf() で変換する js.ValueOf(hoge) でjs.Value 型の値が取れる []interface{} => Array map[string]interface{} => Object js.Callback => function など j s . V a l u e . S e t ( ) を使うと、 自動で j s . V a l u e O f ( ) を使い値を変 換してセットしてくれるので楽です

Slide 13

Slide 13 text

Go => JS の値の変換表 Go JavaScript js.Callback function nil null bool boolean integers and floats number string string []interface{} Array map[string]interface{} Object

Slide 14

Slide 14 text

実際に作ったもの

Slide 15

Slide 15 text

go‑wasm‑todo‑list デモ https://syumai.github.io/go‑wasm‑todo‑list/

Slide 16

Slide 16 text

実装について

Slide 17

Slide 17 text

State p a c k a g e t o d o t y p e S t a t e s t r u c t { l a s t I D i n t t o D o s [ ] T o D o D a t a } v a r s t a t e = S t a t e { } f u n c a p p e n d T o D o ( t i t l e s t r i n g ) { s t a t e . l a s t I D + + s t a t e . t o D o s = a p p e n d ( s t a t e . t o D o s , T o D o D a t a { T i t l e : t i t l e , I D : s t a t e . l a s t I D , } ) }

Slide 18

Slide 18 text

View f u n c T o D o ( p r o p s h . O b j e c t ) h . V N o d e { d o i n g T o D o s , d o n e T o D o s : = s e p a r a t e T o D o s ( s t a t e . t o D o s ) r e t u r n h . H ( " d i v " , n i l , h . H ( " d i v " , h . O b j e c t { " s t y l e " : l i s t C o n t a i n e r S t y l e } , h . H ( " d i v " , h . O b j e c t { " s t y l e " : l i s t S t y l e } , h . H ( " h 3 " , n i l , h . T e x t ( " D o i n g " ) ) , h . H ( " d i v " , n i l , h . T e x t ( " C o u n t : " + s t r c o n v . I t o a ( l e n ( d o i n g h . H ( t o D o L i s t , h . O b j e c t { " t o D o s " : d o i n g T o D o s } ) , ) , h . H ( " d i v " , h . O b j e c t { " s t y l e " : l i s t S t y l e } , h . H ( " h 3 " , n i l , h . T e x t ( " D o n e " ) ) , h . H ( " d i v " , n i l , h . T e x t ( " C o u n t : " + s t r c o n v . I t o a ( l e n ( d o n e T h . H ( t o D o L i s t , h . O b j e c t { " t o D o s " : d o n e T o D o s } ) , ) , ) , ) }

Slide 19

Slide 19 text

App f u n c m a i n ( ) { a p p : = f u n c ( o b j e c t h . O b j e c t ) h . V N o d e { r e t u r n h . H ( " d i v " , n i l , h . H ( " h 2 " , n i l , h . T e x t ( " T o D o L i s t " ) ) , h . H ( t o d o . T o D o , n i l ) , h . H ( " a " , h . O b j e c t { " h r e f " : " h t t p s : / / g i t h u b . c o m / s y u m a i / g o - w h . T e x t ( " S h o w t h e c o d e o n G i t H u b " ) , ) , ) } c o r e . S e t R o o t C o m p o n e n t ( a p p ) c o r e . U p d a t e ( ) s e l e c t { } }

Slide 20

Slide 20 text

別の書き方をすると… ※ このコー ドはイメー ジです f u n c m a i n ( ) { a p p : = f u n c ( o b j e c t h . O b j e c t ) h . V N o d e { r e t u r n ( < d i v > < h 2 > T o D o L i s t < / h 2 > < t o d o . T o D o / > < a h r e f = " h t t p s : / / g i t h u b . c o m / s y u m a i / g o - w a s m - t o d o - l i s t / " S h o w t h e c o d e o n G i t H u b < / a > < / d i v > ) } c o r e . S e t R o o t C o m p o n e n t ( a p p ) c o r e . U p d a t e ( ) s e l e c t { } }

Slide 21

Slide 21 text

何をやっているのか Hyperscript をGo 用に実装した Go の関数でHTML を表現できる 仕組みとしては、React やHyperapp などのJSX => Hyperscript 変換 を行っているフレー ムワー クと同じ 単一のState からDOM 全体を構成するアプリケー ションが作れる Go だけでリッチなFrontend アプリケー ションの実装が出来る!

Slide 22

Slide 22 text

go‑hyperscript https://github.com/syumai/go‑hyperscript f u n c H ( t a g i n t e r f a c e { } , a t t r s O b j e c t , c h i l d r e n . . . V N o d e ) V N o d e { . . . } 第一引数にタグ名 (or Component) 第二引数に属性 第三引数以降は子のVNode を渡す 属性を受け取って、VNode を返す関数はComponent として扱える

Slide 23

Slide 23 text

さっきのView f u n c T o D o ( p r o p s h . O b j e c t ) h . V N o d e { d o i n g T o D o s , d o n e T o D o s : = s e p a r a t e T o D o s ( s t a t e . t o D o s ) r e t u r n h . H ( " d i v " , n i l , h . H ( " d i v " , h . O b j e c t { " s t y l e " : l i s t C o n t a i n e r S t y l e } , h . H ( " d i v " , h . O b j e c t { " s t y l e " : l i s t S t y l e } , h . H ( " h 3 " , n i l , h . T e x t ( " D o i n g " ) ) , h . H ( " d i v " , n i l , h . T e x t ( " C o u n t : " + s t r c o n v . I t o a ( l e n ( d o i n g h . H ( t o D o L i s t , h . O b j e c t { " t o D o s " : d o i n g T o D o s } ) , ) , h . H ( " d i v " , h . O b j e c t { " s t y l e " : l i s t S t y l e } , h . H ( " h 3 " , n i l , h . T e x t ( " D o n e " ) ) , h . H ( " d i v " , n i l , h . T e x t ( " C o u n t : " + s t r c o n v . I t o a ( l e n ( d o n e T h . H ( t o D o L i s t , h . O b j e c t { " t o D o s " : d o n e T o D o s } ) , ) , ) , ) }

Slide 24

Slide 24 text

困ったこと wasm のサイズがでかい minimum でも1.3MB、 複数package をimport すると10MB を超 えることも Gzip で圧縮すると20% 程度にはなります TinyGo ( 埋め込み用のGo 互換コンパイラ) でコンパイルすると 非常に小さいサイズ ( 数10KB~) になるらしい 試してみたもののまだ動かせてないです

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

困ったこと テストが困難 syscall/js をimport しているとamd64 でコンパイル出来ない G O O S = j s G O A R C H = w a s m g o t e s t . . . しても動かない go‑hyperscript では、js.Value 相当のinterface を定義してtest 時 にはモックするようにしました Go 本体のsyscall/js にはtest が書いてあるので、 何かいい方法が あるのかも

Slide 27

Slide 27 text

今後の展望 現状、go‑hyperscript ではDOM の生成しか対応出来ていない UI の更新時は、DOM を丸っと消して再生成している… 汗 差分更新を実装中です! https://twitter.com/__syumai/status/1073283389975744512

Slide 28

Slide 28 text

最後に 言語の枠にとらわれないFrontend 開発を楽しくやっていきましょ う!

Slide 29

Slide 29 text

ご清聴ありがとうございました!