WebAssembly is one of the modern technologies designed for running more languages on the browser with Javascript interoperability.
WebAssembly (WASM) is a platform-independent, binary instruction format for stack-based virtual machines designed as a portable compilation target for programming languages to run on enabling environments (i.e., the web and server apps).
With WASM, you can run several programming languages, including Go, on your browser and harness the features of the language. Also, interoperate with Javascript on the web.
Getting Started With WebAssembly in Go
Go provides first-class support for using WebAssembly in your Go applications, you only need to make a few configurations and compile Go code into WebAssembly.
You’ll need to make a few configurations to transpile your Go code into WebAssembly. You’ll have to change your Go architecture GOARCH environment variable to wasm and Go operating system GOOS variable to js.
Run this command in the terminal of your working directory to make these configurations.
Set GOARCH=wasm GOOS=js
The next step is to transpile your Go code into a WebAssembly .wasm file. Run this command to transpile your main.go file to a file named lib.wasm
go build -o lib.wasm main.go
On running the command, you’ll find a lib.wasm in your working directory.
You need to copy the WebAssembly file accompanying your Go installation into your working directory to execute the WebAssembly file with NodeJS on a web page.
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
The command copies the wasm_exec.js file to your working directory and serves as the entry point to your application.
You can now use the wasm_exec.js script to execute your WASM files with Go and make DOM API calls.
node wasm_exec.js main.wasm
Starting a Web Server to Host the Website
Add this code from the Go authors to an HTML file in your working directory to instantiate a WebAssembly data stream with the instantiateStreaming method.
<!DOCTYPE html>
<!--
Copyright 2018 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
--><html>
<head>
<meta charset="utf-8" />
<title>Go wasm</title>
</head>
<body>
<script src="wasm_exec.js"></script>
<script>
if (!WebAssembly.instantiateStreaming) {
WebAssembly.instantiateStreaming = async (resp, importObject) => {
const source = await (await resp).arrayBuffer();
return await WebAssembly.instantiate(source, importObject);
};
}
const go = new Go();
let mod, inst;
WebAssembly.instantiateStreaming(fetch("lib.wasm"), go.importObject).then(
result => {
mod = result.module;
inst = result.instance;
document.getElementById("runButton").disabled = false;
}
);
async function run() {
await go.run(inst);
inst = await WebAssembly.instantiate(mod, go.importObject);
}
</script>
<button onClick="run();" id="runButton" disabled>Run</button>
</body>
</html>
The HTML code is from the Go Authors, for instantiating a WebAssembly stream that connects your Go code to the webpage.
Starting a Web Server to Run the Page
You’ll set up the server with the http package. Import the http package and the log package for logging possible errors to the console.
import (
"log"
"net/http"
)
You can declare variables for the server address and directory of the files you want to serve on the address.
var (
serverAddr = ":8080"
directory = "."
)
You can use the FileServer method of the http package to serve files in a specified directory. The FileServer method takes in the directory and returns a file server instance.
func main() {
serveFiles := http.FileServer(http.Dir(directory))
if err := http.ListenAndServe(serverAddr, serveFiles); err != nil {
log.Fatalln(err)
}
}
In the main function, you declared a file server instance variable to serve the files in the root directory. The ListenAndServe method serves the files in the specified directory on the specified port.
WebAssembly Functions in Go
Go provides functionality for calling JS functions and interacting with the DOM in the syscall/js package.
The js package provides access to WebAssembly host environments on the js/wasm architecture. You’ll need to have your development environment set up to the GOARCH=wasm GOOS=js to access and use the package.
You can use the various methods in the package to interact with your webpage. Here’s how you can register functions with the js package.
func print(this js.Value, i []js.Value) interface{} {
return js.ValueOf(i[:])
}
The print function on registration as a call-back function will output the data passed to the function in the browser console.
You can register call-back functions with the Set method of the Global method of the js package. The Set method takes in the function identifier and a call-back function instance.
func RegisterCallbackFunctions() {
js.Global().Set("print", js.FuncOf(print))
}
The RegisterCallbackFunctions method registers the print function as a call-back function that you can use in the browser console.
WebAssembly Is an Experimental Feature in Many Languages, Including Go
WebAssembly features are relatively new to many languages, especially since the language recently became a W3C standard. The js package is experimental, and the package is exempt from the Go compatibility promise.