Overview
Beef up your development abilities with AssemblyScript and jump into high performant javascript & typescript modules without any previous knowledge of how to program assembly; with all of the benefits -- mostly ;) AssemblyScript targets WebAssembly's feature set specifically, giving developers low-level control over their code. Being a variant of TypeScript makes it easy to compile to WebAssembly without learning a new language. Integrates with the existing Web ecosystem - no heavy toolchains to set up. Simply npm install it!
Live Editor
Introduction
AssemblyScript compiles a strict variant of TypeScript (a typed superset of JavaScript) to WebAssembly using Binaryen, looking like:
export function fib(n: i32): i32 {
var a = 0, b = 1
if (n > 0) {
while (--n) {
let t = a + b
a = b
b = t
}
return b
}
return a
}
asc fib.ts -b fib.wasm -O3
Its architecture differs from a JavaScript VM in that it compiles a program ahead of time, quite similar to other static compilers. One can think of it as a mix of TypeScript's syntax and C's capabilities.
In a nutshell
On top of WebAssembly types, it not only provides low-level built-ins to access WebAssembly features directly, making it suitable as a thin layer on top of Wasm, but also comes with its own JavaScript-like standard library, making it suitable for non-browser use cases, along a relatively small managed runtime (with memory management and garbage collection) enabling the creation of programs that look and feel much like TypeScript.
For example, on the lowest level, memory can be accessed using the load<T>(offset)
and store<T>(offset, value)
built-ins that compile to WebAssembly instructions directly
store<i32>(8, load<i32>(0) + load<i32>(4))
while the standard library not only provides optimized native Math implementations (both double and single precision) but also implementations of ArrayBuffer, Uint8Array, String, Map etc. on a higher level:
var view = new Int32Array(12)
view[2] = view[0] + view[1]
In turn it also comes with a bunch of features JavaScript doesn't have, mostly out of necessity, like the ability to declare operator overloads that arrays for example use as an implementation helper. It's not quite a subset, not quite a superset, but rather a variant.
As of today, the compiler still has its limitations and we are patiently waiting for and prototyping future WebAssembly features (marked as 🦄 throughout the documentation) to see where these can help.
Sounds appealing to you? Read on!
Quick Start
Paving the way to what might be your first AssemblyScript module.
Prerequisites
The following assumes that a recent version of Node.js (version 12.x+) and its package manager npm (comes with Node.js) are installed, with the commands below executed in a command prompt. Basic knowledge about writing and working with TypeScript modules, which is very similar, is a plus.
Setting up a new project
To get started with AssemblyScript, switch to a new directory and initialize a new node module:
npm init
Now install both the loader and the compiler using npm. Let's assume that the compiler is not required in production and make it a development dependency:
npm install --save @assemblyscript/loader
npm install --save-dev assemblyscript
::: tip
If you need a specific version of the loader and/or the compiler, append the respective version number as usual.
:::
Once installed, the compiler provides a handy scaffolding utility to quickly set up a new AssemblyScript project, for example in the directory of the just initialized node module:
npx asinit .
It automatically creates the recommended directory structure and configuration files:
This command will make sure that the following files exist in the project
directory '/path/to/mymodule':
./assembly
Directory holding the AssemblyScript sources being compiled to WebAssembly.
./assembly/tsconfig.json
TypeScript configuration inheriting recommended AssemblyScript settings.
./assembly/index.ts
Example entry file being compiled to WebAssembly to get you started.
./build
Build artifact directory where compiled WebAssembly files are stored.
./build/.gitignore
Git configuration that excludes compiled binaries from source control.
./index.js
Main file loading the WebAssembly module and exporting its exports.
./tests/index.js
Example test to check that your module is indeed working.
./asconfig.json
Configuration file defining both a 'debug' and a 'release' target.
./package.json
Package info containing the necessary commands to compile to WebAssembly.
Do you want to proceed? [Y/n]
Once initialized, edit the sources in assembly/
, tweak compiler options in asconfig.json
to fit your needs, and run the build command to compile your module to WebAssembly:
npm run asbuild
Next steps
Once compiled, you may run the tests in tests/index.js
:
npm test
add imports to the generated index.js
(instantiates the module and re-exports it):
...
const imports = {
"assembly/index": {
declarredImportedFunction: function(...) { ... }
}
};
...
and ultimately use your WebAssembly module like a normal node module:
const myModule = require("path/to/mymodule");
myModule.add(1, 2);
::: tip NOTE
Your module's exports only understand integers and floats for now, with strings and objects being passed as pointers, but we'll get into that later when covering the loader.
:::
Enjoy :)
Even more reading material at our GitHub Repos
And don't forget to stop by our Discord server for live help and additional resources. Be sure to follow me for updates and tips on accelerating your webdev with AssemblyScript and WebAssembly. Thank you for reading, and happy coding.
Discussion (1)
Very interesting... WebAssembly continues getting new use cases as people experiment with it. Happy coding, indeed!