Node.js with WebAssembly

WebAssembly is a high-performance assembly-like language that can be compiled from various languages, including C/C++, Rust, and AssemblyScript. Currently, it is supported by Chrome, Firefox, Safari, Edge, and Node.js!

The WebAssembly specification details two file formats, a binary format called a WebAssembly Module with a .wasm extension and corresponding text representation called WebAssembly Text format with a .wat extension.

Key Concepts

  • Module - A compiled WebAssembly binary, ie a .wasm file.
  • Memory - A resizable ArrayBuffer.
  • Table - A resizable typed array of references not stored in Memory.
  • Instance - An instantiation of a Module with its Memory, Table, and variables.

In order to use WebAssembly, you need a .wasm binary file and a set of APIs to communicate with WebAssembly. Node.js provides the necessary APIs via the global WebAssembly object.

console.log(WebAssembly);
/*
Object [WebAssembly] {
  compile: [Function: compile],
  validate: [Function: validate],
  instantiate: [Function: instantiate]
}
*/

Generating WebAssembly Modules

There are multiple methods available to generate WebAssembly binary files including:

  • Writing WebAssembly (.wat) by hand and converting to binary format using tools such as wabt
  • Using emscripten with a C/C++ application
  • Using wasm-pack with a Rust application
  • Using AssemblyScript if you prefer a TypeScript-like experience

Some of these tools generate not only the binary file, but the JavaScript "glue" code and corresponding HTML files to run in the browser.

How to use it

Once you have a WebAssembly module, you can use the Node.js WebAssembly object to instantiate it.

// Assume add.wasm file exists that contains a single function adding 2 provided arguments
const fs = require('node:fs');

// Use the readFileSync function to read the contents of the "add.wasm" file
const wasmBuffer = fs.readFileSync('/path/to/add.wasm');

// use the WebAssembly.instantiate method to instantiate the WebAssembly module
WebAssembly.instantiate(wasmBuffer).then(wasmModule => {
  // Exported function lives under instance.exports object
  const { add } = wasmModule.instance.exports;
  const sum = add(5, 6);
  console.log(sum); // Outputs: 11
});

Interacting with the OS

WebAssembly modules cannot directly access OS functionality on its own. A third-party tool Wasmtime can be used to access this functionality. Wasmtime utilizes the WASI API to access the OS functionality.

Resources