From 5a5d3084d519b6b8fe15f4a3bd86c62898a34957 Mon Sep 17 00:00:00 2001 From: Johan Brandhorst Date: Sun, 23 Jun 2019 16:11:22 +0100 Subject: [PATCH] Add vugu example --- Makefile | 8 +++ README.md | 5 ++ go.mod | 6 +- go.sum | 26 ++++++++ vugu/index.html | 32 +++++++++ vugu/main.go | 27 ++++++++ vugu/root.go | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ vugu/root.vugu | 64 ++++++++++++++++++ 8 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 vugu/index.html create mode 100644 vugu/main.go create mode 100644 vugu/root.go create mode 100644 vugu/root.vugu diff --git a/Makefile b/Makefile index 40b250f..eff1946 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,14 @@ ebiten: clean cp ./ebiten/index.html ./html/index.html cp $$(go env GOROOT)/misc/wasm/wasm_exec.js ./html/wasm_exec.js +.PHONY: vugu +vugu: clean + GO111MODULE=on go get github.com/vugu/vugu/cmd/vugugen + vugugen --skip-go-mod --skip-main ./vugu/ + GOOS=js GOARCH=wasm go build -o ./html/main.wasm ./vugu/ + cp ./vugu/index.html ./html/ + cp $$(go env GOROOT)/misc/wasm/wasm_exec.js ./html/wasm_exec.js + test: clean GOOS=js GOARCH=wasm go test -c -o ./html/test.wasm ./test/ diff --git a/README.md b/README.md index dfbdd8d..10e5177 100644 --- a/README.md +++ b/README.md @@ -92,3 +92,8 @@ by [Justin Clift](https://github.com/justinclift). A short demo of using the [Ebiten game engine](https://github.com/hajimehoshi/ebiten) to create a WebGL based flappy bird clone. Copied from the Ebiten examples. + +### Vugu + +An example of a [Vugu](https://www.vugu.org/) application reading the latest +bitcoin price. diff --git a/go.mod b/go.mod index 983774b..dcb2bd4 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module github.com/johanbrandhorst/wasm-experiments go 1.12 require ( - github.com/hajimehoshi/ebiten v1.9.3 // indirect - golang.org/x/image v0.0.0-20190618124811-92942e4437e2 // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 + github.com/hajimehoshi/ebiten v1.9.3 + github.com/vugu/vugu v0.0.0-20190518235128-5a84f26390d1 // indirect + golang.org/x/image v0.0.0-20190618124811-92942e4437e2 ) diff --git a/go.sum b/go.sum index 14d88ae..ad77035 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,21 @@ +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f h1:7MsFMbSn8Lcw0blK4+NEOf8DuHoOBDhJsHz04yh13pM= github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/gofrs/flock v0.7.0 h1:pGFUjl501gafK9HBt1VGL1KCOd/YhIooID+xgyJCf3g= github.com/gofrs/flock v0.7.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c h1:16eHWuMGvCjSfgRJKqIzapE78onvvTbdi1rMkU00lZw= github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherwasm v0.1.1/go.mod h1:kx4n9a+MzHH0BJJhvlsQ65hqLFXDO/m256AsaDPQ+/4= github.com/gopherjs/gopherwasm v1.0.0/go.mod h1:SkZ8z7CWBz5VXbhJel8TxCmAcsQqzgWGR/8nMhyhZSI= github.com/gopherjs/gopherwasm v1.1.0 h1:fA2uLoctU5+T3OhOn2vYP0DVT6pxc7xhTlBB1paATqQ= github.com/gopherjs/gopherwasm v1.1.0/go.mod h1:SkZ8z7CWBz5VXbhJel8TxCmAcsQqzgWGR/8nMhyhZSI= +github.com/hajimehoshi/bitmapfont v1.1.1 h1:H1wQ6QXA8kSp+plARsIMCTVb5iOZHq/OP3uyL5NzLuU= github.com/hajimehoshi/bitmapfont v1.1.1/go.mod h1:Hamfxgney7tDSmVOSDh2AWzoDH70OaC+P24zc02Gum4= github.com/hajimehoshi/ebiten v1.9.3 h1:YijWGMBwH2XA1ZytUQFy33UDHeCSS6d4JZKH1wq38O0= github.com/hajimehoshi/ebiten v1.9.3/go.mod h1:XxiJ4Eltvb1KmcD0i6F81eIB1asJhK47y5DC+FPkyso= @@ -20,9 +28,19 @@ github.com/jfreymuth/oggvorbis v1.0.0 h1:aOpiihGrFLXpsh2osOlEvTcg5/aluzGQeC7m3uY github.com/jfreymuth/oggvorbis v1.0.0/go.mod h1:abe6F9QRjuU9l+2jek3gj46lu40N4qlYxh2grqkLEDM= github.com/jfreymuth/vorbis v1.0.0 h1:SmDf783s82lIjGZi8EGUUaS7YxPHgRj4ZXW/h7rUi7U= github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/vugu/vugu v0.0.0-20190518235128-5a84f26390d1 h1:Iowi+7qqrJr/6RmZFIM8g6n6e8TENUNiOxex1xG/NHA= +github.com/vugu/vugu v0.0.0-20190518235128-5a84f26390d1/go.mod h1:JXaMmpEMpofCzJj8TmSWeLDxAajs4a4wrac5VYwj4A8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/exp v0.0.0-20180710024300-14dda7b62fcd h1:nLIcFw7GiqKXUS7HiChg6OAYWgASB2H97dZKd1GhDSs= golang.org/x/exp v0.0.0-20180710024300-14dda7b62fcd/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20180926015637-991ec62608f3/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= @@ -30,10 +48,18 @@ golang.org/x/image v0.0.0-20190118043309-183bebdce1b2/go.mod h1:ux5Hcp/YLpHSI86h golang.org/x/image v0.0.0-20190618124811-92942e4437e2 h1:fqF3kMQ0tlBEpnfxavzOrjqW5gokBwllwOABYxETOMA= golang.org/x/image v0.0.0-20190618124811-92942e4437e2/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/mobile v0.0.0-20180806140643-507816974b79/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190127143845-a42111704963 h1:2HSxAhImj2OpXsNjXSqfnv1xtqeCpDjwPB3o1DnQqKM= golang.org/x/mobile v0.0.0-20190127143845-a42111704963/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190328230028-74de082e2cca h1:hyA6yiAgbUwuWqtscNvWAI7U1CtlaD1KilQ6iudt1aI= +golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190203050204-7ae0202eb74c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190202235157-7414d4c1f71c/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190407030857-0fdf0c73855b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/vugu/index.html b/vugu/index.html new file mode 100644 index 0000000..24e11cc --- /dev/null +++ b/vugu/index.html @@ -0,0 +1,32 @@ + + + + + + + + +
+ +
+ + + + diff --git a/vugu/main.go b/vugu/main.go new file mode 100644 index 0000000..a90b115 --- /dev/null +++ b/vugu/main.go @@ -0,0 +1,27 @@ +// +build js,wasm + +package main + +import ( + "log" + "os" + + "github.com/vugu/vugu" +) + +func main() { + rootInst, err := vugu.New(&Root{}, nil) + if err != nil { + log.Fatal(err) + } + + env := vugu.NewJSEnv("#target", rootInst, vugu.RegisteredComponentTypes()) + env.DebugWriter = os.Stdout + + for ok := true; ok; ok = env.EventWait() { + err = env.Render() + if err != nil { + log.Fatal(err) + } + } +} diff --git a/vugu/root.go b/vugu/root.go new file mode 100644 index 0000000..df46632 --- /dev/null +++ b/vugu/root.go @@ -0,0 +1,172 @@ +package main + +// DO NOT EDIT: This file was generated by vugu. Please regenerate instead of editing or add additional code in a separate file. + +import "fmt" +import "reflect" +import "github.com/vugu/vugu" + +import "encoding/json" +import "net/http" +import "log" + +type RootData struct { + bpi bpi + isLoading bool +} + +type bpi struct { + Time struct { + Updated string `json:"updated"` + } `json:"time"` + BPI map[string]struct { + Code string `json:"code"` + Symbol string `json:"symbol"` + RateFloat float64 `json:"rate_float"` + } `json:"bpi"` +} + +func (data *RootData) HandleClick(event *vugu.DOMEvent) { + data.bpi = bpi{} + + go func(ee vugu.EventEnv) { + ee.Lock() + data.isLoading = true + ee.UnlockRender() + + res, err := http.Get("https://api.coindesk.com/v1/bpi/currentprice.json") + if err != nil { + log.Printf("Error fetch()ing: %v", err) + return + } + defer res.Body.Close() + + var newb bpi + err = json.NewDecoder(res.Body).Decode(&newb) + if err != nil { + log.Printf("Error JSON decoding: %v", err) + return + } + + ee.Lock() + defer ee.UnlockRender() + data.bpi = newb + data.isLoading = false + }(event.EventEnv()) +} + +var _ vugu.ComponentType = (*Root)(nil) + +func (comp *Root) BuildVDOM(dataI interface{}) (vdom *vugu.VGNode, css *vugu.VGNode, reterr error) { + data := dataI.(*RootData) + _ = data + _ = fmt.Sprint + _ = reflect.Value{} + event := vugu.DOMEventStub + _ = event + var n *vugu.VGNode + n = &vugu.VGNode{Type: vugu.VGNodeType(3), Data: "div", DataAtom: vugu.VGAtom(92931), Namespace: "", Attr: []vugu.VGAttribute{vugu.VGAttribute{Namespace: "", Key: "class", Val: "demo-comp"}}} + vdom = n + { + parent := n + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + if data.isLoading { + n = &vugu.VGNode{Type: vugu.VGNodeType(3), Data: "div", DataAtom: vugu.VGAtom(92931), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + { + parent := n + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "Loading...", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + } + } + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + if len(data.bpi.BPI) > 0 { + n = &vugu.VGNode{Type: vugu.VGNodeType(3), Data: "div", DataAtom: vugu.VGAtom(92931), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + { + parent := n + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t\t", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + n = &vugu.VGNode{Type: vugu.VGNodeType(3), Data: "div", DataAtom: vugu.VGAtom(92931), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + { + parent := n + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "Updated: ", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + n = &vugu.VGNode{Type: vugu.VGNodeType(3), Data: "span", DataAtom: vugu.VGAtom(40708), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + n.InnerHTML = fmt.Sprint(data.bpi.Time.Updated) + } + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t\t", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + n = &vugu.VGNode{Type: vugu.VGNodeType(3), Data: "ul", DataAtom: vugu.VGAtom(42754), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + { + parent := n + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t\t\t", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + for key, value := range data.bpi.BPI { + _, _ = key, value + n = &vugu.VGNode{Type: vugu.VGNodeType(3), Data: "li", DataAtom: vugu.VGAtom(45570), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + { + parent := n + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t\t\t\t", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + n = &vugu.VGNode{Type: vugu.VGNodeType(3), Data: "span", DataAtom: vugu.VGAtom(40708), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + n.InnerHTML = fmt.Sprint(key) + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: " ", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + n = &vugu.VGNode{Type: vugu.VGNodeType(3), Data: "span", DataAtom: vugu.VGAtom(40708), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + n.InnerHTML = fmt.Sprint(fmt.Sprint(value.Symbol, value.RateFloat)) + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t\t\t", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + } + } + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t\t", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + } + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + } + } + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + n = &vugu.VGNode{Type: vugu.VGNodeType(3), Data: "button", DataAtom: vugu.VGAtom(102662), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + // @click = { data.HandleClick(event) } + { + var i_ interface{} = data + idat_ := reflect.ValueOf(&i_).Elem().InterfaceData() + var i2_ interface{} = data.HandleClick + i2dat_ := reflect.ValueOf(&i2_).Elem().InterfaceData() + n.SetDOMEventHandler("click", vugu.DOMEventHandler{ + ReceiverAndMethodHash: uint64(idat_[0]) ^ uint64(idat_[1]) ^ uint64(i2dat_[0]) ^ uint64(i2dat_[1]), + Method: reflect.ValueOf(data).MethodByName("HandleClick"), + Args: []interface{}{event}, + }) + } + if false { + // force compiler to check arguments for type safety + data.HandleClick(event) + } + { + parent := n + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "Fetch Bitcoin Price Index", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + } + n = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n", DataAtom: vugu.VGAtom(0), Namespace: "", Attr: []vugu.VGAttribute(nil)} + parent.AppendChild(n) + } + return +} + +type Root struct {} + +func (ct *Root) NewData(props vugu.Props) (interface{}, error) { return &RootData{}, nil } + +func init() { vugu.RegisterComponentType("root", &Root{}) } diff --git a/vugu/root.vugu b/vugu/root.vugu new file mode 100644 index 0000000..de39f36 --- /dev/null +++ b/vugu/root.vugu @@ -0,0 +1,64 @@ +
+
Loading...
+
+
Updated:
+
    +
  • + +
  • +
+
+ +
+ +