-
Notifications
You must be signed in to change notification settings - Fork 17.7k
WebAssembly
Go 1.11 adds an experimental port to WebAssembly.
WebAssembly is described on its home page as:
WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.
This page will be updated over time with more information relevant to Go's support for WebAssembly.
NOTE: if you ever set the GOROOT
environment variable to the path of an earlier Go SDK version other than the version of the go
command, please unset this environment variable to avoid problems in the following tutorial.
To compile a basic Go package for the web:
package main
import "fmt"
func main() {
fmt.Println("Hello, WebAssembly!")
}
Set GOOS=js
and GOARCH=wasm
environment variables to compile for WebAssembly:
$ GOOS=js GOARCH=wasm go build -o main.wasm
That will build the package and produce an executable WebAssembly module file main.wasm. The .wasm file extension will make it easier to serve it over HTTP with the correct Content-Type header later on. To execute main.wasm in a browser, we'll also need a JavaScript support file and an HTML page that connects everything together.
Copy the JavaScript support file:
$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
Create an index.html
file:
<html>
<head>
<meta charset="utf-8">
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});
</script>
</head>
<body></body>
</html>
(If your browser doesn't yet support WebAssembly.instantiateStreaming
, you can use a polyfill.)
Then serve those three files (index.html
, wasm_exec.js
, and main.wasm
) to a web browser. For example, with goexec
:
$ goexec 'http.ListenAndServe(":8080", http.FileServer(http.Dir(".")))'
(Or use your own basic HTTP server command.)
Finally, navigate to http://localhost:8080/index.html, open the JavaScript debug console, and you should see the output. You can modify the program, rebuild main.wasm
, and refresh to see new output.
It's possible to execute compiled WebAssembly modules using Node.js rather than a browser. The go_js_wasm_exec
script in misc/wasm
directory of the Go installation can be used with -exec
flag of the go
command.
Install node
and make sure it's in your PATH
. Set -exec
flag to the location of go_js_wasm_exec
:
$ GOOS=js GOARCH=wasm go run -exec="$(go env GOROOT)/misc/wasm/go_js_wasm_exec" .
Hello, WebAssembly!
$ GOOS=js GOARCH=wasm go test -exec="$(go env GOROOT)/misc/wasm/go_js_wasm_exec"
PASS
ok example.org/my/pkg 0.800s
Adding 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:
$ export PATH="$PATH:$(go env GOROOT)/misc/wasm"
$ GOOS=js GOARCH=wasm go run .
Hello, WebAssembly!
$ GOOS=js GOARCH=wasm go test
PASS
ok example.org/my/pkg 0.800s
See https://godoc.org/syscall/js.
Alternatively, a library for streamlining DOM manipulation is in development.
WebAssembly doesn't yet have any support for debuggers, so you'll need to use the good 'ol println()
approach for now to display output on the JavaScript console.
An official WebAssembly Debugging Subgroup has been created to address this, with some initial investigation and proposals under way:
- WebAssembly Debugging Capabilities Living Standard (source code for the doc)
- DWARF for WebAssembly Target (source code for the doc)
Please get involved and help drive this if you're interested in the Debugger side of things. 😄
- Shimmer - Image transformation in wasm using Go
-
GoWasm Experiments - Demonstrates working code for several common call types
- bouncy
- rainbow-mouse
- repulsion
-
bumpy
- Uses the 2d canvas, and a 2d physics engine. Click around on the screen to create objects then watch as gravity takes hold!
- arty (NEW)
-
Drawing simple 3D objects on the 2D canvas (source code)
- Displays wireframe solids on the 2d canvas, using basic matrix maths. Use wasd/keypad keys to rotate.
- Gomeboycolor-wasm - WASM port of an experimental Gameboy Color emulator. The matching blog post contains some interesting technical insights.
- Basic triangle (source code) - Creates a basic triangle in WebGL
- Rotating cube (source code) - Creates a rotating cube in WebGL
- Splashy (source code) - Click around on the screen to generate paint...
- Configuring GoLand for WebAssembly - Shows the exact steps needed for getting Wasm working in GoLand
If 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 here.
The Go 1.11 release has a bug which can generate incorrect wasm code in some (rare) circumstances.
If your go code compiles to wasm without problem, but produces an error like this when run in the browser:
CompileError: wasm validation error: at offset 1269295: type mismatch: expression has type i64 but expected f64
Then you're probably hitting this bug.
The fix has been added to both the Go 1.11 release and master branches, so re-compiling Go from either of those will solve the problem.