Webassembly is a great innovation but the majority of modules are made with C++, Rust or GO, and as javascript developers having to maintain two codebases for one project is hard, fortunately that is where AssemblyScript comes in, assemblyscript compiles typescript to wasm and this opens up webassembly to all javascript developers.
Before assemblyscript arrived we had to learn C++ before we could use webassembly but now we have the means of getting into the webassembly ecosystem.
To better understand this environment we will need to ask ourselves a few questions.
1: What can we gain from webassembly?
A huge plus we get from webassembly is the performance boost, webassembly is up to 32x faster than javascript and this allows javascript apps to run at near-native performance.
Native apps made with javascript are often criticized for being slow and unresponsive, especially in low power devices despite the constant performance improvements being shipped by the developers, so having webassembly will allow these apps to run a lot faster.
2: What can we do with webassembly?
There are a lot of things that can be done with webassembly, some of which include
Data Science.
Graphic Design.
Game Development.
Virtual Reality.
Platform Emulation. There is a Windows 2000 virtual machine that is written in webassembly
This list can go on for a while but that will make this post too long, so here is a link to its use cases.
3: How is support for webassembly?
Webassembly has a very active community behind it, there are a lot of developers working on great projects like.
ASM-DOM: A webassembly virtual DOM for building C++ SPAs
Blazor: An experimental web UI framework using C#/Razor
Yew: A rust framework for making web apps
go-vdom-wasm: An experimental virtual DOM for golang and WASM
Asmble: Webassembly to JVM bytecode compiler
Wasmer: A standalone JIT WebAssembly runtime A similar project is wasmjit
pywasm: A webassembly interpreter written in python
wac: A webassembly interpreter written in C. Supports SDL!
This means our modules can also fit into a bigger picture and practically run everywhere
4: How do we get started?
The only way to get started is by using assemblyscript and it is very easy to set up.
Step 1: install
We install assemblyscript by running
$ npm i AssemblyScript/assemblyscript -g
This installs a few commands.
- asc: This is the assemblyscript compiler, it compiles typescript files to wasm binaries.
$ asc -h
SYNTAX
asc [entryFile ...] [options]
EXAMPLES
asc hello.ts
asc hello.ts -b hello.wasm -t hello.wat
asc hello1.ts hello2.ts -b -O > hello.wasm
- asinit: Sets up a new assemblyscript project or updates an existing one
$ asinit -h
Sets up a new AssemblyScript project or updates an existing one.
For example, to create a new project in the current directory:
asinit .
Step 2: Initialize project
To initialize a project we run
$ asinit my-project
This creates a new project for us, but we have to manually install dependencies
$ cd my-project && npm install
Step 3: Build
The asinit
command takes care of adding build scripts to our project so all we have to do is run
$ npm run asbuild
Examples
1: Pointers
Web assembly uses a stack-based virtual machine and this means it uses an array-like structure called a stack to store variables, a problem with this is that we will eventually run into pointers and javascript does not play well with pointers.
Scenario: We have a wasm library compiled from assemblyscript that returns a very important string.
export function return_string(): string{
return "Important stuff";
}
And we use it in our javascript file like this
const wasmModule = await WebAssembly.instantiateStreaming(fetch('simple.wasm'), {})
const importantResult = wasmModule.instance.exports.return_string();
console.log(importantResult); //=> 8
The code above will run with no issues but what gets logged in the console is not the string but a pointer to the string and if we look at our memory, we will find that it looks like this.
"\0f\00\00\00I\00m\00p\00o\00r\00t\00a\00n\00t\00 \00s\00t\00u\00f\00f";
Instead of loading the wasm binary directly via WebAssembly.instantiateStreaming
, we can load it with assemblyscript itself and that will help us with those pesky pointers.
import { instantiateStreaming } from "assemblyscript/lib/loader";
const wasmModule = await instantiateStreaming(fetch('simple.wasm'), {})
const importantResult = wasmModule.getString(wasmModule.return_string());
console.log(importantResult); //=> Important stuff
Example 2: DOM
As a javascript developer, using the DOM is essential but webassembly has no straight forward way of doing this, so different languages have different ways of getting around the problem.
- C++ (emscripten)
auto root = emscripten::val::global("document").call<emscripten::val>(
"getElementById",
std::string("root")
);
- GO (syscall/js)
var root = js.Global().Get("document").Call("getElementById", "root")
- Rust (wasm_bindgen)
let document = web_sys::window().unwrap().document().unwrap();
let root = document.get_element_by_id("root").unwrap();
We can also achieve this but it will take a bit more effort. The first thing we need to do is provide the module a method it can use to manipulate the DOM.
import { instantiateStreaming } from "assemblyscript/lib/loader";
const wasmModule = await instantiateStreaming(fetch('simple.wasm'), {
index: {
changeDiv: (id, value)=>{
var div = document.getElementById(wasmModule.getString(id));
div.innerHTML = wasmModule.getString(value);
}
}
})
Then use it in our module
declare function changeDiv(id: string, value: string): void;
export function set_hello_message(): void {
changeDiv("helloDiv","Hello from WASM");
}
Conclusion
WASM is fast, safe and reliable so having a way to use it without leaving our comfort zone is very encouraging.
Thanks for reading!!!!
The original version of this post was, in all honesty, a very sour look at the situation and I am glad @jtenner pointed that out. I hope this shows a better view
Top comments (5)
Asking and requiring AssemblyScript to support reference types before they are supported in the Web Assembly Specification is asking a lot for an MVP.
For instance, you personally can fix your problems by using the AssemblyScript loader provided in the
"assemblyscript/lib/loader"
module.These criticisms levied against AssemblyScript are not valid, because AssemblyScript is also young, and is worked on by a very dedicated group of developers. Strings are stored as
utf-16
and encoding and decoding strings was one of the very first features they supported.As for speed, there are examples of emulators like wasmboy which is a very good proof of concept that AssemblyScript can be used in high performance situations.
I have personally worked on an RPC library called
as2d
, located here, which emulates theCanvasRenderingContext2D
stack machine and performs a virtual diffing algorithm that reduces JavaScript function calls to the canvas prototype by 40% for common use cases and memory consumption by nearly 50% when drawing to canvas.I doubt writing an article and claiming something "sucks" in this way will be helpful. We all value speed, efficiency, and code that delivers great user experience. I don't think there's a need to act this way, because the purpose of criticism is to make things better. Not worse.
There are plenty of things wrong with AssemblyScript, and you have stated none of them here.
Hope this helps,
-Josh
Thanks, this really helped. I now understand that looking at assemblyscript as a disadvantage is not fair and the opposite should have been the case, i personally use assemblyscript and instead of outlining its shortcomings I should have acknowledged the fact that whatever the case it does a good job at what it promises. Once again thanks for the feedback, it really helped to hear from someone who better understands the inner workings of such projects and I will rewrite this post to be a fair representation of the situation
Please do a great job. I know you will.
Thank you for the kind response.
-Josh
.Net 6 and VS2022 just released a week ago. Blazor is now a major player. Able to compile C# Wasm to any OS. The first true write once run anywhere toil for Webbrowsers. It is also able to create desktop like apps similar to Electron with 1/4 the size. Simply amazing.
I am relatively new to this wasm tech. Is it possibe to perform the compilation of c/cpp to wasm module on the browser instead of running a shell script/binary (emcc)?