WebAssembly excursion with Go

This post shows you how easily it is to compile a WebAssembly module using Go with the latest patches as language.

I’ve been watching the WebAssembly (Wasm) support issue for Go for a long time without trying any patches out. WebAssembly support would be a great benefit for the Go and web community as it allows different languages and technologies to be used crossplatform and sandboxed in a standard webbrowser. Completly without Flash, Silverlight and all other painful stuff. Even without transpiling to JavaScript. It’s a real solution, not a workaround.

Building Go

Building Go is pretty easy and takes less than five minutes on my mid-end laptop. Just clone the repository and run the build script. That’s it. But not all patches are merged into upstream yet so I will clone Richard Musiol s repository, as he is the leading one who is porting Go to Wasm and will maintain the port:

$ git clone git@github.com:neelance/go.git newgo
$ cd newgo/src/
$ git rev-parse HEAD
d7841c75357e82fb6b880bbc84d36bd28d825847
$ git checkout wasm-wip
$ ./all.bash
$ export PATH=/home/djboris/newgo/bin:$PATH
$ go version
go version devel +d7841c7535 Sat May 19 13:15:47 2018 +0200 linux/amd64

Go code for WebAssembly

This example code should be compiled to a WebAssemble module:

package main
import "fmt"
func main() {
fmt.Println(Add(21, 21))
}
func Add(a, b int) int {
return a + b
}

As crosscompiling code for WebAssembly is exactly the same as for other architectures in Go, you must only set two environment variables and run the usual build command:

$ GOARCH=wasm GOOS=js go build -o main.wasm main.go

This will generate main.wasm which will be loaded and executed by the browser. Its MIME type is application/wasm so it must be served with the according Content-Type or the browser will complain.

Combining the things

My first try was a week ago on a older revision of the wasm-wip branch. So Firefox printed an error to the console when I tried to execute it using the MDN examples:

TypeError: import object field 'go' is not an Object

Sadly the main.wasm binary had imports which couldn’t be satisfied:

wasm-dump -x main.wasm # go get github.com/go-interpreter/wagon/cmd/wasm-dump

After that I tried to mock the non existing functions for the importObject but before I had a running version, a useful commit came in which fitted the gap. Combining the provided wasm_exec.js with the following html does the trick.

<html>
<body>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch('main.wasm'), go.importObject).then(function(dat) {
go.run(dat.instance);
});
</script>
</body>
</html>

After serving wasm_exec.js, index.htmland main.wasm, the developer console said 42. The WebAssembly module was executed and my first first WebAssembly excursion was successful too :)

Acknowledgement

I would like to thank Richard Musiol for his great work making WebAssembly a build target for Go!

Like what you read? Give Boris Djurdjevic a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.