Zig and WebAssembly in the browser

I'm starting to learn the Zig programming language, and wanted to see how easy it is to load it in the browser with WebAssembly. I noticed that the official documentation only includes a Node.js example, so I thought I'd write up an example for the browser here.

The math.zig file looks the same as the official example:

extern fn print(i32) void;

export fn add(a: i32, b: i32) void {
    print(a + b);
}

Essentially we're exporting the add() function written in Zig, and using a function called print() that we have to define in JavaScript.

To compile it, run

zig build-lib math.zig -target wasm32-freestanding -dynamic -rdynamic

The JavaScript file index.js looks like this:

const imports = {
  env: {
    print: (result) => { 
      document.getElementById('text').innerHTML = `The result is ${result}`;
    }
  }
};

try {
  const response = await fetch("math.wasm");
  const bytes = await response.arrayBuffer();
  const result = await WebAssembly.instantiate(bytes, imports);
  const add = result.instance.exports.add;
  add(1, 2);
} catch (err) {
  console.log(err);
}

In short, we can use the built-in fetch() to get the math.wasm file we compiled in the previous step. We then instantiate the WebAssembly code, and we can use the add() function that we wrote in Zig. The print() function gets defined as part of the imports object.

All that's left is to create a simple index.html:

<!doctype html>
<html>
  <head>
    <title>Zig in the browser</title>
  </head>
  <body>
  	<div id="text"></div>
    <script type="module" src="index.js"></script>
  </body>
</html>

Take note that we're defining index.js as a module, so that we can use top-level await in JavaScript.

The easiest way to start up a simple web server to run the code is

python -m http.server

which you can then access in your browser by going to http://localhost:8000.

Thoughts? Discuss... if you have a write.as account.

#zig #webassembly