WebAssembly (WASM) begon als een manier om C++ in de browser te draaien. In 2026 draait het overal - browsers, servers, edge-netwerken, embedded apparaten - en drijft het enkele van de meest veeleisende applicaties op het web aan. De rendering-engine van Figma, Adobe Photoshop op het web, de videoverwerking van Google Meet en het edge-computeplatform van Cloudflare draaien allemaal op WebAssembly.
Chrome Platform Status plaatst WASM op ongeveer 5,5% van alle Chrome-paginaladingen begin 2026, gestegen van 4,5% het jaar ervoor. Met WASM 3.0 als W3C-standaard en WASI op weg naar versie 1.0 heeft het ecosysteem een keerpunt bereikt.
Deze gids behandelt alles wat je moet weten om te beginnen met bouwen met WebAssembly.
Wat is WebAssembly?
WebAssembly is een binair instructieformaat ontworpen als compilatiedoel. Je schrijft code in een hogere programmeertaal (Rust, C, C++, Go, Kotlin), compileert het naar .wasm en draait het in elke omgeving die een WASM-runtime heeft - browsers, Node.js, Cloudflare Workers, Wasmtime of Wasmer.
Hoe het werkt
WASM is een stack-gebaseerde virtuele machine. Functies duwen waarden op een operandenstapel en halen ze er weer af. De host-runtime (V8 in Chrome, SpiderMonkey in Firefox) JIT-compileert de WASM-bytecode naar native machinecode, wat verklaart waarom de prestaties bijna native zijn.
Belangrijke kenmerken:
- Sandboxed uitvoering: WASM-modules kunnen alleen toegang krijgen tot resources die de host expliciet toestaat. Geen bestandssysteem, geen netwerk, geen OS-toegang tenzij toegestaan. Dit is fundamenteel anders dan native code.
- Lineair geheugen: een enkele aaneengesloten
ArrayBufferdie wordt gedeeld tussen WASM en de host. Complexe data (strings, structs) wordt doorgegeven door naar het geheugen te schrijven en een pointer te delen. - Typebeperkt: WASM ondersteunt native slechts vier typen:
i32,i64,f32,f64. Al het andere (strings, arrays, objecten) vereist codering via lineair geheugen of het Component Model. - Portabel: dezelfde
.wasm-binary draait op elk platform met een WASM-runtime, zonder hercompilatie.
WASM vs JavaScript
WASM vervangt JavaScript niet. Het vult het aan.
| Aspect | JavaScript | WebAssembly |
|---|---|---|
| Parsing | Parsen + compileren tijdens runtime | Voorgecompileerde binary, alleen decoderen |
| Uitvoeringssnelheid | JIT-geoptimaliseerd, variabel | Bijna native, consistent |
| Opstarttijd | Snel voor kleine scripts | Snelle decodering, voorspelbaar |
| DOM-toegang | Direct | Indirect (via JS-gluecode) |
| Best voor | UI, DOM-manipulatie, event-handling | CPU-intensieve berekeningen |
| Garbage collection | Ingebouwd | WasmGC (nieuw) of handmatig |
Gebruik JavaScript voor UI- en DOM-werk. Gebruik WASM voor zware berekeningen: beeldverwerking, videocodering, fysicasimulaties, cryptografie, dataverwerking.
WASM 3.0: wat is er nieuw
WebAssembly 3.0 werd in september 2025 een W3C-standaard en standaardiseerde negen features die jarenlang in ontwikkeling waren.
| Feature | Wat het mogelijk maakt |
|---|---|
| WasmGC | Native garbage collection in WASM. Beheerde talen (Java, Kotlin, Dart) kunnen compileren naar WASM zonder hun eigen GC-runtime mee te leveren. Ondersteund in Chrome 119+, Firefox 120+, Safari 18.2+. |
| Exception Handling | Native try/catch in WASM. Voorheen vereisten exceptions dure roundtrips naar JavaScript. |
| Tail Calls | Maakt efficiente recursie mogelijk zonder stack overflow. Cruciaal voor functionele talen. |
| Relaxed SIMD | 128-bit vectorinstructies voor parallelle dataverwerking. Maakt hardwarespecifieke optimalisaties mogelijk. |
| Memory64 | Doorbreekt de 4GB-limiet van lineair geheugen. Vereist voor grootschalige dataverwerking. |
| Multi-memory | Meerdere onafhankelijke geheugenregio's in een module. |
De meest impactvolle is WasmGC. Voorheen betekende het compileren van Java of Kotlin naar WASM dat je een complete garbage collector als onderdeel van de binary moest meeleveren, wat de bestandsgrootte opblies. Nu beheert de GC van de browser het geheugen voor WASM-modules, net zoals het dat doet voor JavaScript.
WASI: WebAssembly buiten de browser
WASM in de browser is krachtig, maar WASI (WebAssembly System Interface) maakt WASM een universele runtime. WASI biedt gestandaardiseerde interfaces voor systeemresources - bestanden, netwerken, klokken, willekeurige getallen - waardoor WASM-modules buiten de browser kunnen draaien.
WASI Preview 2 (de huidige stabiele release) definieert deze interfaces:
wasi:filesystem- bestandsoperaties via capability-handles (niet traditionele file descriptors)wasi:sockets- TCP/UDP-netwerkenwasi:http- HTTP-request/response-verwerkingwasi:clocks- wandklok, monotone klokwasi:random- cryptografische willekeurwasi:cli- commandoregelargumenten, omgevingsvariabelen, stdio
Het sleutelprincipe is capability-gebaseerde beveiliging: een WASM-module kan geen toegang krijgen tot het bestandssysteem tenzij de host expliciet een handle naar een specifieke map toekent. Dit maakt WASI fundamenteel veiliger dan het draaien van native executables.
Het pad naar WASI 1.0
WASI 0.3.0 (met toevoeging van async/concurrency-primitieven) wordt verwacht in 2026, gevolgd door WASI 1.0. De belangrijkste toevoeging is taalgeintegreerd async met zero-copy streaming I/O.
Het Component Model
Kern-WASM-modules kunnen alleen getallen uitwisselen. Het Component Model lost deze beperking op door een rijk typesysteem en een compositielaag boven op WASM toe te voegen.
WIT (WebAssembly Interface Types)
WIT is een Interface Definition Language waarmee componenten hun imports en exports kunnen declareren met rijke typen - strings, records, lijsten, varianten, enums - niet alleen i32 en f64.
// calculator.wit package myorg:calculator@1.0.0; interface operations { record calculation { expression: string, result: f64, timestamp: u64, } add: func(a: f64, b: f64) -> f64; multiply: func(a: f64, b: f64) -> f64; history: func() -> list<calculation>; } world calculator { export operations; }
Toolchains zoals wit-bindgen genereren taalspecifieke bindings uit WIT-bestanden. Een Rust-component en een Python-component kunnen strings, records en lijsten uitwisselen via WIT-contracten zonder dat een van beide de implementatietaal van de ander hoeft te kennen.
Je eerste WASM-module bouwen met Rust
Rust heeft de meest volwassen WASM-tooling. Laten we een praktisch voorbeeld bouwen: een beeldverwerkingsmodule die in de browser draait.
Setup
# Install the WASM target for Rust rustup target add wasm32-unknown-unknown # Install wasm-pack (builds Rust to WASM + generates JS bindings) cargo install wasm-pack # Create a new library project cargo new --lib image-processor cd image-processor
Cargo.toml configureren
[package] name = "image-processor" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2"
De Rust-code schrijven
// src/lib.rs use wasm_bindgen::prelude::*; /// Convert an image buffer to grayscale. /// Input: RGBA pixel data as a flat u8 array (4 bytes per pixel). /// Output: Modified in place for zero-copy performance. #[wasm_bindgen] pub fn grayscale(pixels: &mut [u8]) { for chunk in pixels.chunks_exact_mut(4) { let r = chunk[0] as f32; let g = chunk[1] as f32; let b = chunk[2] as f32; // ITU-R BT.709 luminance coefficients let gray = (0.2126 * r + 0.7152 * g + 0.0722 * b) as u8; chunk[0] = gray; chunk[1] = gray; chunk[2] = gray; // chunk[3] is alpha, leave unchanged } } /// Adjust brightness of an image. /// factor > 1.0 brightens, < 1.0 darkens. #[wasm_bindgen] pub fn adjust_brightness(pixels: &mut [u8], factor: f32) { for chunk in pixels.chunks_exact_mut(4) { chunk[0] = ((chunk[0] as f32 * factor).min(255.0)) as u8; chunk[1] = ((chunk[1] as f32 * factor).min(255.0)) as u8; chunk[2] = ((chunk[2] as f32 * factor).min(255.0)) as u8; } } /// Invert all colors in the image. #[wasm_bindgen] pub fn invert(pixels: &mut [u8]) { for chunk in pixels.chunks_exact_mut(4) { chunk[0] = 255 - chunk[0]; chunk[1] = 255 - chunk[1]; chunk[2] = 255 - chunk[2]; } } /// Calculate the average brightness of an image (0-255). #[wasm_bindgen] pub fn average_brightness(pixels: &[u8]) -> f32 { let mut total: f64 = 0.0; let pixel_count = pixels.len() / 4; for chunk in pixels.chunks_exact(4) { let luminance = 0.2126 * chunk[0] as f64 + 0.7152 * chunk[1] as f64 + 0.0722 * chunk[2] as f64; total += luminance; } (total / pixel_count as f64) as f32 }
Build
wasm-pack build --target web
Dit produceert een pkg/-map met:
image_processor_bg.wasm- de gecompileerde WASM-binaryimage_processor.js- JavaScript-gluecode met TypeScript-definitiespackage.json- klaar om te publiceren op npm
Gebruik in JavaScript
<!DOCTYPE html> <html> <head><title>WASM Image Processor</title></head> <body> <canvas id="canvas" width="800" height="600"></canvas> <button onclick="applyGrayscale()">Grayscale</button> <button onclick="applyBrightness()">Brighten</button> <button onclick="applyInvert()">Invert</button> <script type="module"> import init, { grayscale, adjust_brightness, invert } from "./pkg/image_processor.js"; let ctx; let imageData; async function setup() { await init(); const canvas = document.getElementById("canvas"); ctx = canvas.getContext("2d"); // Load an image onto the canvas const img = new Image(); img.onload = () => { ctx.drawImage(img, 0, 0); imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); }; img.src = "photo.jpg"; } window.applyGrayscale = () => { grayscale(imageData.data); ctx.putImageData(imageData, 0, 0); }; window.applyBrightness = () => { adjust_brightness(imageData.data, 1.3); ctx.putImageData(imageData, 0, 0); }; window.applyInvert = () => { invert(imageData.data); ctx.putImageData(imageData, 0, 0); }; setup(); </script> </body> </html>
Het belangrijkste inzicht: imageData.data is een Uint8ClampedArray ondersteund door een ArrayBuffer. Wanneer het aan WASM wordt doorgegeven, deelt het hetzelfde geheugen - geen kopiering. De Rust-functie wijzigt pixels ter plaatse, en de JavaScript-kant ziet de wijzigingen onmiddellijk.
Low-level: handmatige WASM-instantiatie
Als je wasm-bindgen niet wilt gebruiken, kun je WASM-modules direct instantieren:
const response = await fetch("calculator.wasm"); const { instance } = await WebAssembly.instantiateStreaming(response, { env: { // Functions the WASM module can call log_result: (value) => console.log("Result:", value), }, }); // Call exported functions const { add, multiply } = instance.exports; console.log(add(5, 3)); // 8 console.log(multiply(4, 7)); // 28
Dit is handig wanneer je minimale overhead wilt en geen rijke type-interop nodig hebt.
Prestaties: WASM vs JavaScript
Praktijkbenchmarks tonen significante versnellingen voor CPU-intensieve taken:
| Taak | JavaScript | WASM | Versnelling |
|---|---|---|---|
| 4K-beeldverwerking | 180ms | 8ms (met SIMD) | 22x |
| Beeldschaling (4K) | 250ms | 45ms | 5,5x |
| Fysicasimulatie (10K entiteiten) | Framedrops | Vloeiende 60fps | ~10x |
| JSON-parsing (grote payload) | 12ms | 3ms | 4x |
| Cryptografisch hashing | 45ms | 6ms | 7,5x |
WASM draait op ongeveer 95% van de native codesnelheid. De grootste winst komt van:
- Voorspelbare prestaties (geen JIT-opwarming, geen GC-pauzes)
- SIMD-instructies voor parallelle dataverwerking
- Directe geheugentoegang zonder garbage collector-interferentie
Waar WASM NIET sneller is: DOM-manipulatie, kleine berekeningen, I/O-gebonden taken. JavaScript is hier al voor geoptimaliseerd.
Productietoepassingen
Figma: realtime vectorrendering
De kern-rendering-engine van Figma is C++ gecompileerd naar WASM. Elke vorm, elk verloop en elk effect wordt berekend in WASM en getekend op een Canvas-element. Dit stelt Figma in staat om complexe ontwerpen met duizenden lagen op 60fps in de browser te verwerken - prestaties die onmogelijk zouden zijn in puur JavaScript.
Adobe Photoshop op het web
Adobe heeft belangrijke Photoshop-filters en -tools naar WASM geport met Rust. Hun benchmarks tonen 4K-beeldverwerking in 22ms met WASM SIMD versus 180ms in JavaScript - een 8x verbetering die realtime filtervoorbeelden mogelijk maakt.
Cloudflare Workers
Cloudflare draait WASM-modules in V8-isolates op meer dan 330 edge-locaties. Cold starts zijn 1-5ms (vergeleken met 100-500ms voor containergebaseerd serverless). In februari 2026 hebben ze Llama-3-8b-inferentie over hun edge-netwerk uitgerold met WASM.
Google Meet
Achtergrondvervaging en virtuele achtergronden in Google Meet gebruiken WASM met SIMD voor realtime videoverwerking. De WASM-module verwerkt elk videoframe snel genoeg om vloeiend video op 30fps te behouden.
Browserondersteuning (2026)
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Core WASM | Volledig | Volledig | Volledig | Volledig |
| Threads | Ja | Ja | Ja | Ja |
| SIMD (128-bit) | Ja | Ja | Ja | Ja |
| WasmGC | 119+ | 120+ | 18.2+ | Ja |
| Exception Handling | Ja | Ja | Ja | Ja |
| Memory64 | Ja | Ja | Gedeeltelijk | Ja |
Alle grote browsers ondersteunen WASM volledig. De nieuwere features (WasmGC, Exception Handling) zijn breed beschikbaar.
Tooling-referentie
| Tool | Doel | Installatie |
|---|---|---|
| wasm-pack | Rust naar WASM bouwen, npm-pakketten genereren | cargo install wasm-pack |
| wasm-bindgen | Rust/JS-interop-bindings (gebruikt door wasm-pack) | Dependency in Cargo.toml |
| wasm-opt | Optimalisatie van binaire bestandsgrootte (50%+ reductie) | Onderdeel van Binaryen: brew install binaryen |
| wit-bindgen | Bindings genereren uit WIT-bestanden | cargo install wit-bindgen-cli |
| Wasmtime | Server-side WASM-runtime (referentie-WASI-implementatie) | brew install wasmtime |
| Wasmer | Alternatieve WASM-runtime met WASI-ondersteuning | curl https://get.wasmer.io -sSfL | sh |
| wasm-feature-detect | Runtime browser-feature-detectie | npm install wasm-feature-detect |
Binaire bestandsgrootte optimaliseren
WASM-binaries kunnen groot zijn. Zo verklein je ze:
# Cargo.toml [profile.release] opt-level = "z" # Optimize for size lto = true # Link-time optimization codegen-units = 1 # Better optimization, slower compile strip = true # Strip debug symbols
# Build in release mode wasm-pack build --release --target web # Further optimize with wasm-opt wasm-opt -Oz pkg/image_processor_bg.wasm -o pkg/image_processor_bg.wasm
Een typische Rust-WASM-module gaat van 500KB naar minder dan 50KB met deze optimalisaties.
Startroute
Conclusie
WebAssembly is niet langer experimenteel. Het is een productietechnologie die wordt gebruikt door enkele van de meest veeleisende applicaties op het web. Bijna native prestaties, sandboxed beveiliging en universele portabiliteit - geen enkel ander compilatiedoel biedt je alle drie.
Je hoeft niet je hele applicatie in WASM te herschrijven. Begin met een enkele CPU-intensieve functie - een beeldfilter, een dataparser, een fysicaberekening - compileer het naar WASM en roep het aan vanuit JavaScript. Meet het verschil. Beslis dan waar WASM nog meer kan helpen.
De tooling is volwassen, de browserondersteuning is universeel en het ecosysteem groeit. Als je Rust schrijft, ben je al een commando verwijderd van de browser.
Startchecklist:
- Rust en wasm-pack geinstalleerd
- Eerste WASM-module gebouwd en draaiend in de browser
- JavaScript-interop werkt (WASM aanroepen vanuit JS)
- Release-build met grootte-optimalisaties toegepast
- Prestaties gebenchmarkt tegen puur JavaScript-equivalent
- WASI verkend met Wasmtime voor server-side toepassingen