Introduction to WebAssembly: The Magic of Native Code in Web Apps
So what is WebAssembly?
The above sentence about having
the potential to reshape the entire web development is a serious claim, so you eyebrow might be itching to raise skeptically. Like with all bleeding-edge technologies, WebAssembly often causes confusion among web developers. In order to define this term better, we can first address what WebAssembly is actually not:
- WebAssembly isn’t a programming language.
- WebAssembly isn’t just “C++ in web”.
- WebAssembly isn’t a web technology per se even though it’s called, well, WebAssembly.
With this out of the way, let’s define this term: WebAssembly is a binary instruction format for a stack-based virtual machine. This definition, although brief, holds several key points which can help us:
- It’s a virtual machine — a processor whose purpose is to compile code to real architectures, with portability in mind.
- Binary instructions are represented via a two-symbol system.
As web development progressed, the need for such technology grows proportionally: more and more web developers were needing a tool that would get the job done, all the while satisfying a number of requirements:
- Secure. Must not introduce new vulnerabilities.
- Cross-platform. Performs equally well on various desktop and mobile operating systems.
- Zero configuration.
It just works.
- Development-ready (i.e. provides/supports dev and debugging tools).
Why is WebAssembly such a big deal?
We’ve established that WebAssembly is the promise of unified binary format across platforms, which would even include browsers. This is arguably the most exciting novelty of this technology, similar to the emergence of browser-as-an-application paradigm.
WebAssembly also offers predictable performance — the ability to reduce the difference in browser performance (in some cases from 400% to less than 50%).
This curious phenomenon can be demonstrated by implementing image rotation functionality via
canvas: let the user rotate a 4K image and test it under different browsers. Here are the findings of Google Chrome Labs:
- Browser 1 took 400 milliseconds to rotate the image.
- Browser 2 took 500 seconds.
- Browser 3 took 2,5 seconds.
- Browser 4 took 8 seconds.
Looking at this data, it’s tempting to come up with a conclusion like “Aha, Browser 4 is a prime example of bad engineering!” However, we need to remember that different browsers optimize differently, so Browser 4 isn’t Netscape Navigator v0.7 — it’s just a perfectly capable browser. Under other circumstances, perhaps, Browser 1 would be the slowest one.
Disadvantages and caveats of WebAssembly
- FileSystem → Cookie, LocalStorage, IndexedDB.
- Network → XHR, fetch, WebSocket.
- Random → Math.random().
- Async → Poll + setTimeout().
- 3D → Canvas, WebGL.
We should also mention that WebAssembly isn’t fully supported across all modern browsers. Here’s the data provided by Mozilla Developer Network as of August 2019:
Some awesome use cases of WebAssembly
Squoosh.app: Desktop-level image compression… in web!
In his recent talk
WebAssembly for Web Developers, Surma Surma provided a great breakdown of how WASM helped the team build Squoosh, an image compression web app. On the surface, Squoosh functions like any other image compression solution: you drop some images in → they get compressed → you use them on your website → your users are happy that a small cat picture in the header doesn’t weigh several megabytes.
This functionality may seem redundant, though: doesn’t
canvas already offer image encoding options alongside image encoding options and quality settings?
const canvas = document.querySelector(“canvas”);
canvas.toBlob(callback, “image/jpeg”, 0.5);
Using Emscripten, we first compile the library:
echo "Compiling mozjpeg..."
emconfigure ./configure --without-simd
emmake make libjpeg.la
configure --without-simd part: threads and simd would greatly help to encode, but WebAssembly doesn’t have support for these features… for now, so they’re disabled for safety reasons.
uint8_t* image_buffer = (uint8_t*) malloc();
// ... Use MozJPEG ...
return val(typed_memory_view(size, image_buffer));
After that, an Emscripten C compiler called EMCC will link everything together:
-I node_modules/mozjpeg \
-o ./mozjpeg_enc.js \
-x c++ -std=c++11 \
Golang is at its earliest stages of supporting WA. As Surma Surma, developer advocate for the Open Web Platform at Google, puts it:
True! Golang has (very) experimental WebAssembly support. But Go is a garbage-collected language, so currently, their binaries are pretty big and rather slow, as they have to compile their entire runtime. Just like AssemblyScript, it will get much better once we have native garbage collection in WebAssembly.
ByteFog: Peer-to-peer video-sharing done right
ByteFog is a technology designed to make peer-to-peer video sharing efficient and streamlined. As every streaming service performs poorly under heavy load, ByteFrog addresses this problem by making clients “share” parts of the video with their peers, helping the server and saving its resources. In browsers, this technology was implemented via a browser extension — but then the team decided to rewrite it in WebAssembly.
Here are the advantages of moving the service from browser extension to the web version:
- No installation. Convincing the prospective user to install an extension or an app is a challenge in and of itself. Moving the service to the web version skips this challenge entirely.
- Unified codebase.
- Debugging on every platform simultaneously. As ByteFog offers applications for various platforms (Windows, Linux, macOS, Android, iOS, and web), noticing bugs becomes far easier: while a particular bug may be hard to observe on Platform A, it can be much easier to spot on Platform B.
- Fast releases and updates. Unlike desktop/mobile applications, updating a web app is relatively streamlined.
- Fast feedback which stems from the previous point.
Of course, the number of WebAssembly projects is growing day by day and it’s impossible to cover all of them. Here are some honorable mentions:
- Wasm-ImageMagick: It’s ImageMagick! In Webassembly!
- wasmboy: Gameboy emulator written in WebAssembly. wasmboy is an awesome combination: a blast from the past which will soothe your ears with classic Gameboy sounds and a curious case of Wasm as a technology.
- WOTInspector: This is a service which analyzes match replays from a popular online game World of Tanks. The calculations the service has to do are pretty heavy, so it could very well become a paid platform with all heavy-lifting done on the backend. WOTInspector’s author, however, went for a different route: he created the business logic in C++ and implemented it in WebAssembly, allowing users to carry these computations out on their own devices — and so the service managed to stay free!
- Tried and tested libraries like FFmpeg (video encoding), opus (audio encoding), OpenCV (computer vision) are also available to be implemented in WebAssembly. The sky is the limit!
WebAssembly learning resources
At this point in the article, WebAssembly has finally worked its magic and you’re itching to start learning it. Here’s the catch: you don’t learn WebAssembly per se; instead, you learn a language that can be compiled to it. A good example is Rust which also features a great Getting Started resource.
For a quick dive-in, you can use WasmFiddle — as the name suggests, it’s a code playground which allows you to experiment with WebAssembly without putting a hazard suit on.
WebAssembly is promising to introduce a paradigm shift in the way we develop web apps. With support from web giants like Google and Mozilla, its future is looking even brighter. Let’s recap the article — WebAssembly can be used to…
- Decrease load times.
- Increase execution/calculations speed.
- Utilize C/C++ code in web apps.
Thankfully, you won’t miss out on any groundbreaking changes in the web development sphere — our blog got you covered! 🙂
C# also compiles to WebAssembly. Would be nice to mention the languages we can use to start testing this out. https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor