DEV Community

Mainasara Al-amin Tsowa
Mainasara Al-amin Tsowa

Posted on

The JS developer's view of WASM in 2019

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • 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 .

Enter fullscreen mode Exit fullscreen mode
Step 2: Initialize project

To initialize a project we run

$ asinit my-project
Enter fullscreen mode Exit fullscreen mode

This creates a new project for us, but we have to manually install dependencies

$ cd my-project && npm install
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

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";
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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")
    );
Enter fullscreen mode Exit fullscreen mode
  • GO (syscall/js)
var root = js.Global().Get("document").Call("getElementById", "root")
Enter fullscreen mode Exit fullscreen mode
  • Rust (wasm_bindgen)
let document = web_sys::window().unwrap().document().unwrap();
let root = document.get_element_by_id("root").unwrap();
Enter fullscreen mode Exit fullscreen mode

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);
        }
    }
})
Enter fullscreen mode Exit fullscreen mode

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");
}
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
jtenner profile image
jtenner • Edited

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.

import { instantiateStreaming } from "assemblyscript/lib/loader";

const module = await instantiateStreaming(fetch("my-module.wasm"), imports);
const importantString = module.getString(module.return_string());

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 the CanvasRenderingContext2D 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

Collapse
 
neutrino2211 profile image
Mainasara Al-amin Tsowa

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

Collapse
 
jtenner profile image
jtenner

Please do a great job. I know you will.

Thank you for the kind response.
-Josh

Collapse
 
jwp profile image
John Peters

.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.

Collapse
 
techieexplorer profile image
Iftekharuddin Mohammed • Edited

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)?