UNPKG

4.11 kBMarkdownView Raw
1## Integrating GopherJS with Smartdown in two beers
2
3A couple weeks ago on a November 2017 Friday evening, I set my mind to integrating a non-Javascript language into Smartdown in order to learn/teach such a language via Smartdown. After eliminating ClojureScript, ScalaJS, and KotlinJS via a fairly simple process of determining whether their demos worked offline, I settled on [GopherJS](https://github.com/gopherjs/gopherjs), the Javascript implementation of Go, as a worthy target.
4
5Why? Because the [GopherJS Playground](https://github.com/gopherjs/gopherjs.github.io) worked wonderfully offline, proving that compilation of my Go source code was occurring in the browser, and satisfying my need for such a capability in Smartdown.
6
7### It took more than two beers
8
9I'm going to write a more detailed article about this project, but I eventually succeeded in learning Go, adapting the GopherJS Playground to work as a UI-less body of code, and integrating this code into Smartdown in a reasonable way. This document is an example of the potential of GoDown, the Smartdown+Go integration.
10
11### Producer/Consumer Example
12
13This demonstrates the use of multiple Go packages, the use of the GopherJS DOM package, and the use of channels to communicate between multiple processes.
14
15#### ProducerA
16
17Creates a Button that emits an "A" to the channel
18
19```go/playable/autoplay
20package producerA
21
22import (
23 "honnef.co/go/js/dom"
24 "github.com/gopherjs/gopherjs/js"
25)
26
27func Producer(ch chan string) {
28 d := dom.GetWindow().Document()
29
30 myDivId := js.Global.Get("godownDiv_producerA").String()
31 println("myDivId", myDivId)
32 div := d.GetElementByID(myDivId).(*dom.HTMLDivElement)
33 div.SetInnerHTML("")
34
35 child := d.CreateElement("button").(*dom.HTMLButtonElement)
36 child.Style().SetProperty("color", "purple", "")
37 child.SetTextContent("Produce A")
38 div.AppendChild(child)
39 child.AddEventListener("click", false, func(event dom.Event) {
40 ch <- "A"
41 })
42}
43```
44
45#### ProducerB
46
47Creates a Button that emits a "B" to the channel
48
49```go/playable/autoplay
50package producerB
51
52import (
53 "honnef.co/go/js/dom"
54 "github.com/gopherjs/gopherjs/js"
55)
56
57func Producer(ch chan string) {
58 d := dom.GetWindow().Document()
59
60 myDivId := js.Global.Get("godownDiv_producerB").String()
61 println("myDivId", myDivId)
62 div := d.GetElementByID(myDivId).(*dom.HTMLDivElement)
63 div.SetInnerHTML("")
64
65 child := d.CreateElement("button").(*dom.HTMLButtonElement)
66 child.Style().SetProperty("color", "purple", "")
67 child.SetTextContent("Produce B")
68 div.AppendChild(child)
69 child.AddEventListener("click", false, func(event dom.Event) {
70 ch <- "B"
71 })
72}
73```
74
75
76#### Consumer
77
78Reads from the channel and displays a log of all received messages.
79
80
81```go/playable/autoplay
82package consumer
83
84import (
85 "honnef.co/go/js/dom"
86 "github.com/gopherjs/gopherjs/js"
87)
88
89func Consumer(ch chan string) {
90 d := dom.GetWindow().Document()
91 consumed := ""
92 myDivId := js.Global.Get("godownDiv_consumer").String()
93 println("myDivId", myDivId)
94 div := d.GetElementByID(myDivId).(*dom.HTMLDivElement)
95
96 for {
97 div.SetInnerHTML("<h1>" + consumed + "</h1>")
98 consumedChar, more := <- ch
99 if more {
100 consumed += consumedChar
101 } else {
102 break
103 }
104 }
105}
106```
107
108
109#### Main program invokes Producers and Consumer and then Chills
110
111All Go programs start with `main`. In this example, we just use `main` to tie together the various producer/consumer components and give them a shared channel for communication. It is totally possible, and reasonable to combine `producerA` and `producerB` into a parametrized package `producer`; but this demo evolved to show off the multi-package capability.
112
113
114```go/playable/autoplay
115package main
116
117import (
118 "producerA"
119 "producerB"
120 "consumer"
121 "github.com/gopherjs/gopherjs/js"
122)
123
124var ch chan string
125
126func main() {
127 js.Global.Set("Godown_Shutdown", js.InternalObject(func(msg string) {
128 close(ch)
129 }))
130
131 ch = make(chan string, 5)
132 go producerA.Producer(ch)
133 go producerB.Producer(ch)
134 go consumer.Consumer(ch)
135
136 println("All Done")
137}
138
139```
140
141---
142
143[Back to Home](:@Home)