With every major browser now supporting WebAssembly, it’s time to start thinking seriously about writing client-side apps for the web that can be compiled as WebAssembly.
Developers should consider WebAssembly for performance-intensive use cases such as games, music streaming, video editing, and CAD applications. Many web services have already made the move, such as Google Earth. Figma, a collaborative drawing and diagramming app, turned to WebAssembly to cut load times and execution speed even when WebAssembly was relatively new.
How WebAssembly works
WebAssembly, developed by the W3C, is in the words of its creators a “compilation target.” Developers don’t write WebAssembly directly; they write in the language of their choice, which is then compiled into WebAssembly bytecode. The bytecode is then run on the client—typically in a web browser—where it’s translated into native machine code and executed at high speed.
WebAssembly use cases
WebAssembly has been designed with a number of performance-intensive, browser-based use cases in mind: games, music streaming, video editing, CAD, encryption, and image recognition, to name just a few.
More generally, it’s instructive to focus on these three areas when determining your particular WebAssembly use case:
- Porting a desktop application to a web environment. Many of the technology demos for asm.js and WebAssembly fall into this category. WebAssembly can provide a substrate for apps that are more ambitious than just a GUI presented via HTML. See the demos of WebDSP and Windows 2000 in the browser, for two examples.
WebAssembly language support
WebAssembly isn’t meant to be written directly. As the name implies, it’s more like an assembly language, something for the machine to consume, than a high-level, human-friendly programming language. WebAssembly is closer to the intermediate representation (IR) generated by the LLVM language-compiler infrastructure, than it is like C or Java.
Thus most scenarios for working with WebAssembly involve writing code in a high-level language and turning that into WebAssembly. This can be done in any of three basic ways:
- Direct compilation. The source is translated into WebAssembly by way of the language’s own compiler toolchain. Rust, C/C++, Kotlin/Native, and D now all have native ways to emit Wasm from compilers that support those languages.
- Third-party tools. The language doesn’t have native Wasm support in its toolchain, but a third-part utility can be used to convert to Wasm. Java, Lua, and the .Net language family all have some support like this.
- WebAssembly-based interpreter. Here, the language itself isn’t translated into WebAssembly; rather, an interpreter for the language, written in WebAssembly, runs code written in the language. This is the most cumbersome approach, since the interpreter may be several megabytes of code, but it allows existing code written in the language to run all but unchanged. Python (by way of PyScript, for example) and Ruby both have interpreters translated to Wasm.
WebAssembly is still in the early stages. The WebAssembly toolchain and implementation remain closer to proof-of-concept than production technology. That said, WebAssembly’s custodians have their sights set on making WebAssembly more useful through a series of initiatives:
Garbage collection primitives
WebAssembly doesn’t directly support languages that use garbage-collected memory models. Languages like Lua or Python can be supported only by restricting feature sets or by embedding the entire runtime as a WebAssembly executable. But there is work under way to support garbage-collected memory models regardless of the language or implementation.
Native support for threading is common to languages such as Rust and C++. The absence of threading support in WebAssembly means that whole classes of WebAssembly-targeted software can’t be written in those languages. The proposal to add threading to WebAssembly uses the C++ threading model as one of its inspirations.
Bulk memory operations and SIMD
Bulk memory operations and SIMD (single instruction, multiple data) parallelism are must-haves for applications that grind through piles of data and need native CPU acceleration to keep from choking, like machine learning or scientific apps. Proposals are on the table to add these capabilities to WebAssembly via new operators.
High-level language constructs
Many other features being considered for WebAssembly map directly to high-level constructs in other languages.
- Exceptions can be emulated in WebAssembly, but cannot be implemented natively via WebAssembly’s instruction set. The proposed plan for exceptions involves exception primitives compatible with the C++ exception model, which could in turn be used by other languages compiled to WebAssembly.
- Reference types make it easier to pass around objects used as references to the host environment. This would make garbage collection and a number of other high-level functions easier to implement in WebAssembly.
- Tail calls, a design pattern used in many languages.
- Functions that return multiple values, e.g., via tuples in Python or C#.
- Sign-extension operators, a useful low-level math operation. (LLVM supports these as well.)
Debugging and profiling tools