Generate and run WebAssembly code using Go
Tags: go, webassembly
Published: 2020-03-22 19:38:54

Dive in the features of WebAssembly is not the focus along these few lines and for sure I'm not the most suitable person to do that. My purpose is to talk about how WebAssembly and Go can work together, since I'm interested in all the possible applications of Go language and recently I discovered this new solution that I'll try to show here step by step.
For those who have never heard WebAssembly I think could be fair a brief presentation of about what that standard is and what is used for.

## A few word on WebAssembly

Probably the best approach to start with is take a look at the official website https://webassembly.org/.
`
WebAssembly 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.
`
Let's try to analyze the keywords.
The first thing to know is that the WebAssembly code is compiled to binary format, the file generated after the build has `.wasm` extension. 
The JavaScript engine decodes and interprets the .wasm file once it will be loaded by the web page. To execute the code a stack-based virtual machine is intended as a pointer that maintains the position of the executed code and a virtual control keep track of blocks within the code as though a stack. 
The portability concerns the possibility to execute efficiently the wasm file on a variety of operating systems and architectures. WebAssembly is not tied to a specific environment and generate the binary file is easy starting from source code written in high-level languages.   
WebAssembly in nutshell:  
* useful for developers that want to run code on a web browser without needs third party plugin, the major browsers natively supports WebAssembly
* it is fast, WebAssembly code runs at a speed that is pretty close to the native speed
* the .wasm binary can be generated using a wide range of languages like C, C++ and Rust. Now even in Go.
* the browser's JavaScript engine will interpret the .wasm file and execute the functions. 

## Build the WebAssembly binary file using GO code

The WebAssembly compile target is available starting from Go 1.11. 
The Go 1.12 version add some breaking changes in `syscall/js`, the package that will be briefly explore below. In order to proceed with this post without wasting time fixing errors, be ensure you have installed Go 1.12 or higher. You can quickly check the version installed with the command `go version`. 
Now we can spent a few minutes exploring the algorithm we will use to obtain our purpose. Thinking about the easiest solution, we can read two integers received as parameters from the web page and print out the sum of them. Let's take a look at the code before moving to the build process for the .wasm file. 
```
package main

import (
	"fmt"
	"strconv"
	"syscall/js"
)

var done = make(chan struct{})

func main() {
	callback := js.FuncOf(printResult)
	defer callback.Release()
	setResult := js.Global().Get("setResult")
	setResult.Invoke(callback)
	<-done
}

func printResult(value js.Value, args []js.Value) interface{} {
	value1 := args[0].String()
	v1, err := strconv.Atoi(value1)
	if err != nil {
		fmt.Errorf("error %s", err.Error())
		return err
	}
	value2 := args[1].String()
	v2, err := strconv.Atoi(value2)
	if err != nil {
		fmt.Errorf("error %s", err.Error())
		return err
	}

	fmt.Printf("%d\n", v1+v2)
	done <- struct{}{}
	return nil
}
``` 
The `printResult` function didn't do anything else but get the values from JavaScript argument, parse it to int and print the sum. The channel is used to notify the callback has been called.   
In the main function there are maybe the darker aspects of this silly example. First of all, let's see the package imported: `syscall/js`, here is the link to get more information https://golang.org/pkg/syscall/js/.
`
The package gives access to the WebAssembly host environment when using the js/wasm architecture. Its API is based on JavaScript semantics.
`
`js.FuncOf(printResult)` wraps the Go function `printResult` as a callback and its purpose is the sum operation. The JavaScript's values are passed to that function through `js.Value` array. The `defer callback.Release()` is used to free up resources as soon as the function returns. `setResult` is the JavaScript property used as a resolver of the promise, that wait for the result of the wrapped Go callback. We will better see this aspect later. 
Now it's time to build the wasm file. It's an easy extension of the build command we have already learned to use when compiling Go code. Be careful to specify the js/wasm architecture using GOOS and GOARCH environment variables.
```
GOOS=js GOARCH=wasm go build -o main.wasm toWasm.go
```
* GOOS specifies the operating system, the default value is overwritten with the instance of JavaScript 
* GOARCH the default values specifies the processor architecture, in this case is overwritten with the WebAssembly value.

GOOS and GOARCH specified in the command tells Go to create a WebAssmebly file, without these details the .wasm file won't be created. If everything has been done well, we will find the `main.wasm` file in our directory.  

## Load the build and launch the HTML file

The first step is to copy the main.wasm just generated in the same directory selected to hold the html code as well. After that we need to copy the `wasm_exec.js` file in the same directory, this file is part of the Go installation package. 
Assuming you are already in the working directory, copy and paste the following command.
```
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
```
Now you have both `main.wasm` and `wasm_exec.js` in the same path, there is nothing more to do but add the `index.html`. This is the tree output of my working dir. 

```
$ tree
.
├── index.html
├── main.wasm
└── wasm_exec.js

0 directories, 3 files
```

Thinking about what we need to provide to the `printResult` function, is necessary add two `<input>` to get the values from the web page and a `<button>` to run the sum execution. The sum result will be printed out on the browser console.

Other than that the `index.html` 
* includes the `wasm_exec.js` file we copied before which allowing us to use the `Go()` constructor
* loads the `main.wasm` as source using the `WebAssembly.instantiateStreaming()` method. 

The return values of the `instantiateStreaming()` are `mod = result.module` representing the compiled WebAssembly module and `inst = result.instance` representing the object that contains the exported functions. 
The instance `const go = new Go()` is necessary to run the code exported.
Finally, `run()` is an async function that waits for the result of the promise. The execution of the job is based on passing the values to the Go code. As soon as the promise make the result available, the code is free to reset the instance in order to be ready for the next run `inst = await WebAssembly.instantiate(mod, go.importObject)`.   

```
<html>
    <head>
        <meta charset="utf-8">
        <title>Go WebAssembly</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("main.wasm"), go.importObject).then((result) => {
                mod = result.module;
                inst = result.instance;
            }).catch((err) =>{
                console.error(err)
            });

            var setResult
            async function run() {

                const printResultPromise = new Promise(resolve => {
                    setResult = resolve
                })
                const run = go.run(inst)

                const printResult = await printResultPromise

                printResult(document.querySelector('#value1').value, document.querySelector('#value2').value)
                await run 

                inst = await WebAssembly.instantiate(mod, go.importObject)
            }
        </script>
        <button onClick="run()" id="runButton">Run</button>
        <input id="value1" type="text">
        <input id="value2" type="text">
    </body>

</html>
```
Now we have finished the code review. Let's try the solution loading the `index.html` file on the browser, this will be the outcome.  

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ej1r9k3tj6lsq9j3s4hx.png)

This is a just silly example, but the key is that create some WebAssembly code starting from Go is an easy job because of its cross-compilation capabilities. That open new possibilities leveraging on the browser support no longer for the full benefit of JavaScript only.