As we at e.GO Mobile using web technologies in Node.js context, there is an interesting, and relative new feature, called WebAssembly.

As we have implemented many projects with TypeScript, today I will show how to set up a project that uses WebAssembly modules written in AssemblyScript.

WebAssembly

WebAssembly is a binary instruction format for a stack-based virtual machine. It is designed to be a portable target for the compilation of high-level languages like C, C++, TypeScript (AssemblyScript) and Rust, enabling deployment on the web for client and server applications. It is supported by all major browsers, including Chrome, Firefox, Safari, and Edge.

It is platform-independent, which means that it can be executed on any device, regardless of the operating system or hardware architecture. This is achieved by compiling high-level languages into a binary format that can be executed by a virtual machine. The virtual machine is designed to be fast and efficient, which means that applications written in WebAssembly can run at near-native speeds.

The summary of advantages is:

  • it enables the development of high-performance applications that run very fast (games, image/video processing, etc.)
  • it is platform-independent
  • it runs in browsers and as server code (Node.js / Deno) as well

AssemblyScript

AssemblyScript is almost identical to TypeScript in terms of syntax, but behaves like a statically- and strong-typed language such as C++

For relatively simple applications/modules, the language is sufficient. Additionally, it produces highly optimized WebAssembly byte code compared to compilers that use Rust as the language.

Creating a project

On GitHub you find an example repository which shows how you can setup WebAssembly for a browser and a server application as well.

To create a new project we have to initialize an NPM project with a package.json file:

npm init -y

Remove the -y if you have to define the settings for the project by your own.

With

npm i @assemblyscript/loader
npm i -D assemblyscript

we will install all required modules of AssemblyScript and finally execute

npx asinit .

to create and setup the directory with example files and NPM scripts.

Update example code

The initial code can be found in assembly/index.ts folder.

Change the content to something like this to get a better understanding:

export function pow2(val: i32): i32 {
    return val * val;
}

As you can see, AssemblyScript does not support the types from JavaScript/TypeScript.

As WebAssembly is a low-level language, the data types are also kept very simple. A list of the types supported by AssemblyScript can be found here.

If you change the example code, you have update the test-file tests/index.js as well:

import assert from "node:assert";
import {
    pow2
} from "../build/debug.js";

for (let i = 0; i <= 20; i++) {
    const expected = Math.pow(i, 2);

    assert.strictEqual(pow2(i), expected);
}

You can see that importing a WebAssembly module works in the same way as importing a regular JavaScript module. Additionally the AssemblyScript compiler produces .d.ts declaration files in the build/ folder.

It should be noted that the project, as can be seen from the import-statements, was initialized not as a CommonJS module, but as an ESM module.

Now execute

npm run asbuild
npm run test

to see if everything works fine.

Running

In my demo project I have added/updated the NPM script start and start:web in the package.json file.

While npm run start will run in Node.js environment, npm run start:web will start a web server at http://localhost:3000/ and providing the content of index.html in root folder of the project, which demonstrates how to import a WebAssembly module in a HTML document for a comaptible browser.

The Node.js code can be found in src/index.ts file btw.

Conclusion & outlook

Setting up a WebAssembly project is very easy nowadays, as you can see. The support of languages to compile to WebAssembly is constantly growing.

In addition to TypeScript in the form of AssemblyScript, there are also languages like C/C++, C# or Rust. Compared to AssemblyScript, the latter are more powerful and may produce more byte code under certain circumstances.

The only confusing thing may be that the file extension .ts is used by both the TypeScript compiler and the AssemblyScript compiler. Although they have almost the same syntax, they behave differently. TypeScript is more of a transpiler to JavaScript, while AssemblyScript is a “real” compiler.

As Rust is the currently most popular languge for WebAssembly, I will try to write a small post in one of the next days, which explains how to setup a WebAssembly project with Rust.

Have fun! 🎉