Skip to content

WebAssembly

Kevin Burke edited this page Oct 21, 2018 · 53 revisions

Go 1.11 added 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 assumes a functional Go 1.11 or newer installation. For troubleshooting, see InstallTroubleshooting page.

Example

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.

Executing WebAssembly with Node.js (for go run, go test)

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 is in your PATH. Set the -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

Interacting with the DOM

See https://godoc.org/syscall/js.

Alternatively, a library for streamlining DOM manipulation is in development.

Debugging

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:

Please get involved and help drive this if you're interested in the Debugger side of things. 😄

Go WebAssembly talks

Further reference examples

General

  • Shimmer - Image transformation in wasm using Go

Canvas (2D)

WebGL canvas (3D)

Editor configuration

WebAssembly in Chrome

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.

Known bug

The Go 1.11 and 1.11.1 releases have 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 error.

The fix has been added to both the 1.11.x release and master branches on GitHub, so re-compiling Go from either of those will solve the problem.

Other WebAssembly resources

  • Awesome-Wasm - An extensive list of further Wasm resources. Not Go specific.
Clone this wiki locally