blob: eff97b70d3bd68ac25fff3c9dc2da540dda21d21 [file] [log] [blame]
Justin Cliftc1b68852018-10-26 00:23:01 +11001WebAssembly
2===========
3:toc:
4:toc-title:
5:toclevels: 2
6:icons:
7
8
9# Introduction
10
11Go 1.11 added an experimental port to WebAssembly.
12
13WebAssembly is described on its https://webassembly.org[home page] as:
14
15> WebAssembly (abbreviated _Wasm_) is a binary instruction format for
16> a stack-based virtual machine. Wasm is designed as a portable
17> target for compilation of high-level languages like C/C++/Rust,
18> enabling deployment on the web for client and server applications.
19
20**********************************************************************
Justin Cliftb6813da2018-10-26 12:02:47 +110021If you're new to WebAssembly read the <<Getting Started>> section,
Justin Clift03e0fb22018-10-26 12:04:38 +110022watch some of the https://github.com/golang/go/wiki/WebAssembly#go-webassembly-talks[Go Webassembly talks],
23then take a look at the <<Further examples>> below.
Justin Cliftc1b68852018-10-26 00:23:01 +110024**********************************************************************
25
Justin Cliftbb1ad3d2018-10-26 02:35:20 +110026
Justin Cliftc1b68852018-10-26 00:23:01 +110027# Getting Started
28
29This page assumes a functional Go 1.11 or newer installation. For
30troubleshooting, see the https://github.com/golang/go/wiki/InstallTroubleshooting[Install Troubleshooting]
31page.
32
33To compile a basic Go package for the web:
34
Justin Cliftc1b68852018-10-26 00:23:01 +110035```go
36package main
37
38import "fmt"
39
40func main() {
41 fmt.Println("Hello, WebAssembly!")
42}
43```
44
45Set `GOOS=js` and `GOARCH=wasm` environment variables to compile
46for WebAssembly:
47
48```sh
49$ GOOS=js GOARCH=wasm go build -o main.wasm
50```
51
52That will build the package and produce an executable WebAssembly
53module file named main.wasm. The .wasm file extension will make it
54easier to serve it over HTTP with the correct Content-Type header
55later on.
56
57To execute main.wasm in a browser, we'll also need a JavaScript
58support file, and a HTML page to connect everything together.
59
60Copy the JavaScript support file:
61
62```sh
63$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
64```
65
66Create an `index.html` file:
67
68```HTML
69<html>
70 <head>
71 <meta charset="utf-8">
72 <script src="wasm_exec.js"></script>
73 <script>
74 const go = new Go();
75 WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
76 go.run(result.instance);
77 });
78 </script>
79 </head>
80 <body></body>
81</html>
82```
83
84If your browser doesn't yet support `WebAssembly.instantiateStreaming`,
85you can use a https://github.com/golang/go/blob/b2fcfc1a50fbd46556f7075f7f1fbf600b5c9e5d/misc/wasm/wasm_exec.html#L17-L22[polyfill].
86
87Then serve the three files (`index.html`, `wasm_exec.js`, and
88`main.wasm`) from a web server. For example, with
89https://github.com/shurcooL/goexec#goexec[`goexec`]:
90
91```sh
92$ goexec 'http.ListenAndServe(":8080", http.FileServer(http.Dir(".")))'
93```
94
95Or use your own https://play.golang.org/p/pZ1f5pICVbV[basic HTTP server command].
96
97Finally, navigate to http://localhost:8080/index.html, open the
98JavaScript debug console, and you should see the output. You can
99modify the program, rebuild `main.wasm`, and refresh to see new
100output.
101
102
103# Executing WebAssembly with Node.js
104
105It's possible to execute compiled WebAssembly modules using Node.js
106rather than a browser, which can be useful for testing and automation.
107
108With Node installed and in your `PATH`, set the `-exec` flag to the
109location of `go_js_wasm_exec` when you execute `go run` or `go test`.
110
111By default, `go_js_wasm_exec` is in the `misc/wasm` directory of your
112Go installation.
113
114```
115$ GOOS=js GOARCH=wasm go run -exec="$(go env GOROOT)/misc/wasm/go_js_wasm_exec" .
116Hello, WebAssembly!
117$ GOOS=js GOARCH=wasm go test -exec="$(go env GOROOT)/misc/wasm/go_js_wasm_exec"
118PASS
119ok example.org/my/pkg 0.800s
120```
121
122Adding `go_js_wasm_exec` to your `PATH` will allow `go run` and `go test` to work for `js/wasm` without having to manually provide the `-exec` flag each time:
123
124```
125$ export PATH="$PATH:$(go env GOROOT)/misc/wasm"
126$ GOOS=js GOARCH=wasm go run .
127Hello, WebAssembly!
128$ GOOS=js GOARCH=wasm go test
129PASS
130ok example.org/my/pkg 0.800s
131```
132
Justin Cliftbb1ad3d2018-10-26 02:35:20 +1100133
134# Go WebAssembly talks
135
Justin Cliftbda80042018-11-28 15:47:34 +1100136* https://www.youtube.com/watch?v=4kBvvk2Bzis[Building a Calculator with Go and WebAssembly] (https://tutorialedge.net/golang/go-webassembly-tutorial/[Source code])
Justin Cliftbb1ad3d2018-10-26 02:35:20 +1100137* https://www.youtube.com/watch?v=iTrx0BbUXI4[Get Going with WebAssembly]
138
139
Justin Cliftc1b68852018-10-26 00:23:01 +1100140# Interacting with the DOM
141
142See https://godoc.org/syscall/js.
143
144Alternatively, https://github.com/dennwc/dom[a library for streamlining DOM manipulation]
145is in development.
146
martin-juhlinb16e04c2019-02-21 08:11:30 +0100147There is also a https://gowebapi.github.io/[binding generator] that can be used.
Justin Cliftbb1ad3d2018-10-26 02:35:20 +1100148
149# Editor configuration
150
Justin Cliftfb2e83b2019-01-24 02:27:49 +1100151* https://github.com/golang/go/wiki/Configuring-GoLand-for-WebAssembly[Configuring GoLand and Intellij Ultimate for WebAssembly] - Shows the exact steps needed for getting Wasm working in GoLand and Intellij Ultimate
Justin Cliftbb1ad3d2018-10-26 02:35:20 +1100152
153
154# WebAssembly in Chrome
155
156If you run a newer version of Chrome there is a flag (`chrome://flags/#enable-webassembly-baseline`) to enable Liftoff, their new compiler, which should significantly improve load times. Further info https://chinagdg.org/2018/08/liftoff-a-new-baseline-compiler-for-webassembly-in-v8/[here].
157
158
Justin Cliftc1b68852018-10-26 00:23:01 +1100159# Debugging
160
161WebAssembly doesn't *yet* have any support for debuggers, so you'll
162need to use the good 'ol `println()` approach for now to display
163output on the JavaScript console.
164
165An official https://github.com/WebAssembly/debugging[WebAssembly Debugging Subgroup]
166has been created to address this, with some initial investigation and
167proposals under way:
168
169* https://fitzgen.github.io/wasm-debugging-capabilities/[WebAssembly Debugging Capabilities Living Standard]
170 (https://github.com/fitzgen/wasm-debugging-capabilities[source code for the doc])
171* https://yurydelendik.github.io/webassembly-dwarf/[DWARF for WebAssembly Target]
172 (https://github.com/yurydelendik/webassembly-dwarf/[source code for the doc])
173
174Please get involved and help drive this if you're interested in the Debugger side of things. :smile:
175
Justin Cliftc1b68852018-10-26 00:23:01 +1100176
Justin Cliftbb1ad3d2018-10-26 02:35:20 +1100177# Known bug(s)
178
Justin Cliftb910f042018-11-09 11:50:27 +1100179Go releases prior to 1.11.2 https://github.com/golang/go/issues/27961[have a bug] which can generate incorrect wasm code in some (rare) circumstances.
Justin Cliftbb1ad3d2018-10-26 02:35:20 +1100180
181If your Go code compiles to wasm without problem, but produces an error like this when run in the browser:
182
183```
184CompileError: wasm validation error: at offset 1269295: type mismatch: expression has type i64 but expected f64
185```
186
187Then you're probably hitting this error.
188
Justin Cliftb910f042018-11-09 11:50:27 +1100189The solution is to upgrade to Go 1.11.2 or later.
Justin Cliftbb1ad3d2018-10-26 02:35:20 +1100190
Justin Cliftc1b68852018-10-26 00:23:01 +1100191
192# Further examples
193
194## General
195* https://github.com/agnivade/shimmer[Shimmer] - Image transformation in wasm using Go
196
197## Canvas (2D)
198* https://github.com/stdiopt/gowasm-experiments[GoWasm Experiments] - Demonstrates
199 working code for several common call types
200** https://stdiopt.github.io/gowasm-experiments/bouncy[bouncy]
201** https://stdiopt.github.io/gowasm-experiments/rainbow-mouse[rainbow-mouse]
202** https://stdiopt.github.io/gowasm-experiments/repulsion[repulsion]
Justin Clift41abc962018-10-26 00:25:04 +1100203** https://stdiopt.github.io/gowasm-experiments/bumpy[bumpy] - Uses the 2d canvas, and a 2d physics engine. Click around on the screen to create objects then watch as gravity takes hold!
Justin Cliftc1b68852018-10-26 00:23:01 +1100204** https://stdiopt.github.io/gowasm-experiments/arty/client[arty]
Justin Cliftc1b68852018-10-26 00:23:01 +1100205* https://github.com/djhworld/gomeboycolor-wasm[Gomeboycolor-wasm]
206** WASM port of an experimental Gameboy Color emulator. The https://djhworld.github.io/post/2018/09/21/i-ported-my-gameboy-color-emulator-to-webassembly/[matching blog post]
207 contains some interesting technical insights.
208
209## WebGL canvas (3D)
210* https://bobcob7.github.io/wasm-basic-triangle/[Basic triangle] (https://github.com/bobcob7/wasm-basic-triangle[source code]) - Creates a basic triangle in WebGL
211* https://bobcob7.github.io/wasm-rotating-cube/[Rotating cube] (https://github.com/bobcob7/wasm-rotating-cube[source code]) - Creates a rotating cube in WebGL
212* https://stdiopt.github.io/gowasm-experiments/splashy[Splashy] (https://github.com/stdiopt/gowasm-experiments/tree/master/splashy[source code]) - Click around on the screen to generate paint...
213
Justin Clift1322f1a2018-11-02 14:44:21 +1100214# Reducing the size of Wasm files
215
216At present, Go generates large Wasm files, with the smallest possible size being around ~2MB. If your Go code imports libraries, this file size can increase dramatically. 10MB+ is common.
217
218There are two main ways (for now) to reduce this file size:
219
2201. gz compress the .wasm file - This reduces things reasonably well. For example, the ~2MB (minimum file size) example Wasm will compress down to around 500kB.
221
joonas.fi6583ee62018-12-02 14:14:29 +02002222. Use https://github.com/aykevl/tinygo[TinyGo] to generate the Wasm file instead. TinyGo is a subset of the Go language targeted for embedded devices, and recently added a WebAssembly output target. While it does have limitations (not a full Go implementation), it is still fairly capable and the generated Wasm files are... Tiny. ~10kB isn't unusual. This project is also very actively developed, so its capabilities are expanding out quickly.
Justin Cliftc1b68852018-10-26 00:23:01 +1100223
224# Other WebAssembly resources
225
226* https://github.com/mbasso/awesome-wasm[Awesome-Wasm] - An extensive list of further Wasm resources. Not Go specific.