What is WebAssembly, and what is it not?
WebAssembly (WASM) adds new capabilities to Web applications, but let’s make it clear from the very beginning that it doesn’t replace HTML or Javascript. WebAssembly can’t do anything to a Web App without these two, which is what makes it fundamentally different from earlier plugin technologies like Java Applets, Flash or Silverlight.
And this is a good thing, and it should stay this way, cause if WebAssembly got a way to get direct access to your display, input devices or local storage, it would be a breach to the philosophy of WASM to put security first.
Like these legacy plugin technologies, WebAssembly lets you execute compiled binary code in the browser, making it a compile target for many languages. The possibility to compile C and C++ to WebAssembly makes it possible to make use of the enormous universe of libraries written in these languages directly in the web browser. Just to mention one there is for example WASM-GIT which is a port of the popular GIT library libgit2, written in C, working out of the box when compiled to WebAssembly using Emscripten.
Still this doesn’t mean that the compiled WASM binary of libgit2 can do anything on its own. GIT needs a filesystem to be useful for anything and this is provided in Javascript, and also using the browser storage IndexedDB for persistence. And when it comes to network connectivity for pushing and pulling to remote repositories, we still need to use Web API’s like XHR and fetch and provide this to the WASM library using Javascript.
Every capability needed by the WebAssembly module must be provided from the Javascript that also initializes and starts it. Initially the WASM module can only compute and access it’s designated memory and connectivity to anything else must be provided from Javascript, which again is limited by the WEB-browser sandbox. The legacy plugins lived outside the browser sandbox with potential access to the full device, while WASM is just a compute engine.
And speaking of compute engine, this is where WebAssembly shines. Sometimes computational intensive tasks may have an unpredictable performance in a Just-In-Time compiled language like Javascript, but here’s where WebAssembly makes a difference. WebAssembly binaries are compiled Ahead-Of-Time, meaning performance will be predictable, stable and in most cases faster than Javascript, and even near the performance of native code.
An example of applications in need of such computational power is for example real time audio rendering as done in the WebAssembly Music project. Audio is rendered in short chunks lasting just 3 ms each, so that it’s possible to play notes instantly when pressing the midi keyboard. Such real-time synthesis requires predictable and fast performance, and this is where WebAssembly does what Javascript could not. And when writing new code for such tasks, and not porting existing libraries, it’s good to have the option of other languages than C. For example Rust or AssemblyScript, which was used for writing all the audio synthesis in this project.
But still the WebAssembly here doesn’t replace anything of the traditional Web App parts such as the user interface, networking or storage. This is all handled by Javascript/HTML and the WASM components are only for reusing C libraries or where computationally intensive code is needed.
So what about writing entire Web Apps in WebAssembly?
Well, in general HTML and Javascript is best at this unless:
- you want to port an existing desktop app to the Web
- you want to port legacy plugin based apps such as Java applets, Flash etc.
- you want to reuse browser-side code on the server
- you need to write your web app in another language
You can port desktop apps to the Web by rendering them in an HTML canvas. I will not go into the details about this, but for example desktop applications built with Qt can be ported this way. There are also examples on Java applets ported successfully, and even Flash.
Blazor, which is a .net runtime ported to WASM running in the browser, makes it possible to write an entire client side Web app in C#. It also enables you use the same C# code on the server. Blazor does not run your code in WebAssembly, it’s only the runtime that is WASM which again runs your .net binaries in the browser. So it wouldn’t give you the same performance as a real WASM binary, the purpose here would rather be to reuse .net binaries. Also there are extra overhead when it comes to size of the web application. In the world of progressive web apps we can limit the amount downloaded to only what’s new, but still the initial application to be downloaded package can be quite massive compared to a similar app in plain HTML / JS.
You can of course write your Web app entirely in Rust or C for that matter, by applying the same concept as Blazor generating the HTML contents from WebAssembly. The difference here would be that you would serve your app directly from WASM binaries, and not a runtime for facilitating another type of binary like with Blazor. So much less overhead when it comes to download size, and also better performance. Still, using WebAssembly for controlling the DOM where JavaScript already excels might only give you the benefit of being able to use your favourite language, with the cost of extra obstacles for providing the glue-layer from Web APIs to WASM, increased download size and risk of degraded performance compared to JS for this type of applications.
Speaking of reuse — what about WASM on the server?
WebAssembly on the server is interesting when it comes to running the same code in the browser and on the server, but also for server-side security. The same sandbox that restricts WASM in the browser is also present on the server side. WASM is a good candidate for shipping containers to the cloud, since not only it’s not limited to a CPU architecture, but the container orchestrator would have even more control over capabilities provided to WASM containers, compared to Docker containers.
From my own experience with WASM on the server is the Xapian search index used in Runbox7. I was working with the initial parts of this project that involved running Xapian using WebAssembly both in the browser and on the server. Building the search index for emails server-side, and then transfer the index files to the browser using the same Xapian code on the client-side to search.
Using this approach not only could the C code be reused, but also the Javascript (Typescript) code used to interact with the C library. You could of course ask, why not run Xapian natively on the server, but then again the interaction with NodeJS would be different, and you would rely on a specific operating system version build. And so WASM gives you better portability than using builds for the native platform.
Wrapping up
WebAssembly is great for where computational performance is essential. It’s also excellent for reusing libraries written in other languages, as well as porting legacy applications to the web. If code-sharing with the server is important, and you want to use another language than JS/TS then such language support can provided by WASM, or if you simply want to write as little JS as possible.
Still JS is the most efficient for controlling the DOM and interacting with Web APIs, and WASM can’t do anything without provisioning of capabilities from JS. And keeping it this way is essential for keeping WASM secure compared to plugin-based predecessors.
How to pronounce WASM btw?
W-awesome
:-)