Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upWebAssembly
WebAssembly
Introduction
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.
If you’re new to WebAssembly read the Getting Started section, watch some of the Go Webassembly talks, then take a look at the Further examples below.
Getting Started
This page assumes a functional Go 1.11 or newer installation. For troubleshooting, see the Install Troubleshooting page.
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.wasmThat will build the package and produce an executable WebAssembly module file named 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 a HTML page to connect 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 the three files (index.html, wasm_exec.js, and
main.wasm) from a web server. 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
It’s possible to execute compiled WebAssembly modules using Node.js rather than a browser, which can be useful for testing and automation.
With Node installed and in your PATH, set the -exec flag to the
location of go_js_wasm_exec when you execute go run or go test.
By default, go_js_wasm_exec is in the misc/wasm directory of your
Go installation.
$ 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
Go WebAssembly talks
Interacting with the DOM
Alternatively, a library for streamlining DOM manipulation is in development.
Editor configuration
-
Configuring GoLand and Intellij Ultimate for WebAssembly - Shows the exact steps needed for getting Wasm working in GoLand and Intellij Ultimate
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.
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.
Known bug(s)
Go releases prior to 1.11.2 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 solution is to upgrade to Go 1.11.2 or later.
Further examples
General
-
Shimmer - Image transformation in wasm using Go
Canvas (2D)
-
GoWasm Experiments - Demonstrates working code for several common call types
-
bumpy - Uses the 2d canvas, and a 2d physics engine. Click around on the screen to create objects then watch as gravity takes hold!
-
-
WASM port of an experimental Gameboy Color emulator. The matching blog post contains some interesting technical insights.
-
WebGL canvas (3D)
-
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…
Reducing the size of Wasm files
At 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.
There are two main ways (for now) to reduce this file size:
-
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.
-
Use 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.
Other WebAssembly resources
-
Awesome-Wasm - An extensive list of further Wasm resources. Not Go specific.