Introduction to WebAssembly with Go
Let's offload heavy computation on browser to WebAssembly with Go
Photo by Alexander Shatov on Unsplash
WebAssembly Overview
What is actually WebAssembly? Here is a snippet from webassembly.org official website.
"WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications."
OK that sounds mouthful, basically WebAssembly is open standard technology that allows application to be written in high level language such as Go, Rust, and C++ and then compiled into portable binary code and execute it in web browser.
Unlike Javascript, we can ship application within one single *.wasm
binary file. This means distribution of the application will be faster over the network and broswer can cache the binary.
Use Cases
There still not a lot of use cases to use WebAssembly, but a notable example is when application require operations with 64-bit integers data type. WebAssembly can overcome limited support for 64-bit integers in Javascript as Javascript doesn't have native 64-bit integers, it only support 53-bit integers. Meanwhile, Go have native 64-bit integers support.
Maximum value for an integer with 64-bit is 18,446,744,073,709,551,615 according to Wolfram Alpha
WebAssembly can be used to build performant web application that requires heavy workload beyond Javascript capabilities. Figma uses WebAssembly and achieve 3x faster load albeit it's built with C++ not Go.
Browser Compatibility
Top 4 (Chrome, Firefox, Edge and Safari) browser have perfect compatibility for WebAssembly, while Internet Explorer doesn't support WebAssembly at all. Opera somewhat compatible with WebAssemly but not fully. Here is the detail on Browser Compatibility according to Mozilla.
Go Support for WebAssembly
Go 1.11 added an experimental port to WebAssembly. Go 1.12 has improved some parts of it, with further improvements starting in Go 1.13.
Compiling to *.wasm
Application written with Go can be compiled to WebAssembly by specifying GOOS=js
and GOARCH=wasm
environment variable. Let write some simple Go code.
Prepare a workspace with following structure:
introduction-to-web-assembly-with-go
├── go.mod
├── public
├── server.go
└── wasm
└── main.go
Add content to main.go
package main
import "fmt"
func main() {
fmt.Println("Hello, Go WebAssembly")
}
And then compile it to WebAssembly
$ GOOS=js GOARCH=wasm go build -o ./public/app.wasm ./wasm/main.go
Javascript Support File
Official documentation for WebAssembly in Go mention we need to add Javascript support file to load the WebAssembly binary onto the web page. This Javascript file can be copied from GOROOT
if you already install Go.
$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" ./public/
HTML Boilerplate
Add simple HTML boilerplate to tie up everything together.
<html>
<head>
<meta charset="utf-8" />
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("app.wasm"), go.importObject).then(
(result) => {
go.run(result.instance);
}
);
</script>
</head>
<body></body>
</html>
Create simple static HTTP server on server.go
package main
import (
"fmt"
"net/http"
)
func main() {
err := http.ListenAndServe(":9090", http.FileServer(http.Dir("public/")))
if err != nil {
fmt.Println("Failed to start server", err)
return
}
}
Run go run server.go
and point your browser to localhost:9090
and open browser console, you should see "Hello, Go WebAssembly"
printed.
Example Code
Simple WebAssembly code can be found in this GitHub repository. The file structure should be as follow:
introduction-to-web-assembly-with-go
├── go.mod
├── public
│ ├── app.wasm
│ ├── index.html
│ └── wasm_exec.js
├── server.go
└── wasm
└── main.go
Limitations
While WebAssembly is awesome, but there are some limitations. For example, due to browser strict security policy we cannot write application that interact with the filesystem. I would not go into this too deep, it might worth another post.
Closing
WebAssembly provide versatile solution to offload heavy computation on web pages. This could be applied to games, mathematical calculator, data processing, or even video editor on the web. In my opinion more website will be using WebAssembly in the future. WebAssembly will not replace Javascript for the near future as the ability to interact with DOM still hard to write. Next, I will write on how to interact with WebAssembly from Javascript. Stay tuned!