spinny:~/writing $ vim webassembly-wasm-complete-guide.md
1~2WebAssembly (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.3~4Chrome 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.5~6Deze gids behandelt alles wat je moet weten om te beginnen met bouwen met WebAssembly.7~8## Wat is WebAssembly?9~10WebAssembly 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.11~12```mermaid13graph LR14 Rust[Rust / C / C++] --> Compiler[Compiler]15 Compiler --> WASM[.wasm Binary]16 WASM --> Browser[Browser V8/SpiderMonkey]17 WASM --> Server[Server Wasmtime]18 WASM --> Edge[Edge Cloudflare Workers]19 WASM --> Embedded[Embedded WAMR]20```21~22### Hoe het werkt23~24WASM 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.25~26Belangrijke kenmerken:27~28- **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.29- **Lineair geheugen**: een enkele aaneengesloten `ArrayBuffer` die wordt gedeeld tussen WASM en de host. Complexe data (strings, structs) wordt doorgegeven door naar het geheugen te schrijven en een pointer te delen.30- **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.31- **Portabel**: dezelfde `.wasm`-binary draait op elk platform met een WASM-runtime, zonder hercompilatie.32~33### WASM vs JavaScript34~35WASM vervangt JavaScript niet. Het vult het aan.36~37| Aspect | JavaScript | WebAssembly |38|--------|-----------|-------------|39| **Parsing** | Parsen + compileren tijdens runtime | Voorgecompileerde binary, alleen decoderen |40| **Uitvoeringssnelheid** | JIT-geoptimaliseerd, variabel | Bijna native, consistent |41| **Opstarttijd** | Snel voor kleine scripts | Snelle decodering, voorspelbaar |42| **DOM-toegang** | Direct | Indirect (via JS-gluecode) |43| **Best voor** | UI, DOM-manipulatie, event-handling | CPU-intensieve berekeningen |44| **Garbage collection** | Ingebouwd | WasmGC (nieuw) of handmatig |45~46Gebruik JavaScript voor UI- en DOM-werk. Gebruik WASM voor zware berekeningen: beeldverwerking, videocodering, fysicasimulaties, cryptografie, dataverwerking.47~48## WASM 3.0: wat is er nieuw49~50WebAssembly 3.0 werd in september 2025 een W3C-standaard en standaardiseerde negen features die jarenlang in ontwikkeling waren.51~52| Feature | Wat het mogelijk maakt |53|---------|----------------|54| **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+. |55| **Exception Handling** | Native `try`/`catch` in WASM. Voorheen vereisten exceptions dure roundtrips naar JavaScript. |56| **Tail Calls** | Maakt efficiente recursie mogelijk zonder stack overflow. Cruciaal voor functionele talen. |57| **Relaxed SIMD** | 128-bit vectorinstructies voor parallelle dataverwerking. Maakt hardwarespecifieke optimalisaties mogelijk. |58| **Memory64** | Doorbreekt de 4GB-limiet van lineair geheugen. Vereist voor grootschalige dataverwerking. |59| **Multi-memory** | Meerdere onafhankelijke geheugenregio's in een module. |60~61De 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.62~63## WASI: WebAssembly buiten de browser64~65WASM 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.66~67```mermaid68graph TD69 subgraph "Browser"70 B[WASM Module] --> Web[Web APIs\nDOM, Fetch, Canvas]71 end72~73 subgraph "Server / Edge / Embedded"74 S[WASM Module] --> WASI[WASI Interfaces]75 WASI --> FS[wasi:filesystem]76 WASI --> Net[wasi:sockets]77 WASI --> HTTP[wasi:http]78 WASI --> Clock[wasi:clocks]79 WASI --> Rand[wasi:random]80 end81```82~83WASI Preview 2 (de huidige stabiele release) definieert deze interfaces:84~85- `wasi:filesystem` - bestandsoperaties via capability-handles (niet traditionele file descriptors)86- `wasi:sockets` - TCP/UDP-netwerken87- `wasi:http` - HTTP-request/response-verwerking88- `wasi:clocks` - wandklok, monotone klok89- `wasi:random` - cryptografische willekeur90- `wasi:cli` - commandoregelargumenten, omgevingsvariabelen, stdio91~92Het 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.93~94### Het pad naar WASI 1.095~96WASI 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.97~98## Het Component Model99~100Kern-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.101~102### WIT (WebAssembly Interface Types)103~104WIT 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`.105~106```wit107// calculator.wit108package myorg:calculator@1.0.0;109~110interface operations {111 record calculation {112 expression: string,113 result: f64,114 timestamp: u64,115 }116~117 add: func(a: f64, b: f64) -> f64;118 multiply: func(a: f64, b: f64) -> f64;119 history: func() -> list<calculation>;120}121~122world calculator {123 export operations;124}125```126~127Toolchains 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.128~129## Je eerste WASM-module bouwen met Rust130~131Rust heeft de meest volwassen WASM-tooling. Laten we een praktisch voorbeeld bouwen: een beeldverwerkingsmodule die in de browser draait.132~133### Setup134~135```bash136# Install the WASM target for Rust137rustup target add wasm32-unknown-unknown138~139# Install wasm-pack (builds Rust to WASM + generates JS bindings)140cargo install wasm-pack141~142# Create a new library project143cargo new --lib image-processor144cd image-processor145```146~147### Cargo.toml configureren148~149```toml150[package]151name = "image-processor"152version = "0.1.0"153edition = "2021"154~155[lib]156crate-type = ["cdylib"]157~158[dependencies]159wasm-bindgen = "0.2"160```161~162### De Rust-code schrijven163~164```rust165// src/lib.rs166use wasm_bindgen::prelude::*;167~168/// Convert an image buffer to grayscale.169/// Input: RGBA pixel data as a flat u8 array (4 bytes per pixel).170/// Output: Modified in place for zero-copy performance.171#[wasm_bindgen]172pub fn grayscale(pixels: &mut [u8]) {173 for chunk in pixels.chunks_exact_mut(4) {174 let r = chunk[0] as f32;175 let g = chunk[1] as f32;176 let b = chunk[2] as f32;177 // ITU-R BT.709 luminance coefficients178 let gray = (0.2126 * r + 0.7152 * g + 0.0722 * b) as u8;179 chunk[0] = gray;180 chunk[1] = gray;181 chunk[2] = gray;182 // chunk[3] is alpha, leave unchanged183 }184}185~186/// Adjust brightness of an image.187/// factor > 1.0 brightens, < 1.0 darkens.188#[wasm_bindgen]189pub fn adjust_brightness(pixels: &mut [u8], factor: f32) {190 for chunk in pixels.chunks_exact_mut(4) {191 chunk[0] = ((chunk[0] as f32 * factor).min(255.0)) as u8;192 chunk[1] = ((chunk[1] as f32 * factor).min(255.0)) as u8;193 chunk[2] = ((chunk[2] as f32 * factor).min(255.0)) as u8;194 }195}196~197/// Invert all colors in the image.198#[wasm_bindgen]199pub fn invert(pixels: &mut [u8]) {200 for chunk in pixels.chunks_exact_mut(4) {201 chunk[0] = 255 - chunk[0];202 chunk[1] = 255 - chunk[1];203 chunk[2] = 255 - chunk[2];204 }205}206~207/// Calculate the average brightness of an image (0-255).208#[wasm_bindgen]209pub fn average_brightness(pixels: &[u8]) -> f32 {210 let mut total: f64 = 0.0;211 let pixel_count = pixels.len() / 4;212 for chunk in pixels.chunks_exact(4) {213 let luminance = 0.2126 * chunk[0] as f64214 + 0.7152 * chunk[1] as f64215 + 0.0722 * chunk[2] as f64;216 total += luminance;217 }218 (total / pixel_count as f64) as f32219}220```221~222### Build223~224```bash225wasm-pack build --target web226```227~228Dit produceert een `pkg/`-map met:229- `image_processor_bg.wasm` - de gecompileerde WASM-binary230- `image_processor.js` - JavaScript-gluecode met TypeScript-definities231- `package.json` - klaar om te publiceren op npm232~233### Gebruik in JavaScript234~235```html236<!DOCTYPE html>237<html>238<head><title>WASM Image Processor</title></head>239<body>240 <canvas id="canvas" width="800" height="600"></canvas>241 <button onclick="applyGrayscale()">Grayscale</button>242 <button onclick="applyBrightness()">Brighten</button>243 <button onclick="applyInvert()">Invert</button>244~245 <script type="module">246 import init, { grayscale, adjust_brightness, invert } from "./pkg/image_processor.js";247~248 let ctx;249 let imageData;250~251 async function setup() {252 await init();253 const canvas = document.getElementById("canvas");254 ctx = canvas.getContext("2d");255~256 // Load an image onto the canvas257 const img = new Image();258 img.onload = () => {259 ctx.drawImage(img, 0, 0);260 imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);261 };262 img.src = "photo.jpg";263 }264~265 window.applyGrayscale = () => {266 grayscale(imageData.data);267 ctx.putImageData(imageData, 0, 0);268 };269~270 window.applyBrightness = () => {271 adjust_brightness(imageData.data, 1.3);272 ctx.putImageData(imageData, 0, 0);273 };274~275 window.applyInvert = () => {276 invert(imageData.data);277 ctx.putImageData(imageData, 0, 0);278 };279~280 setup();281 </script>282</body>283</html>284```285~286Het 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.287~288## Low-level: handmatige WASM-instantiatie289~290Als je `wasm-bindgen` niet wilt gebruiken, kun je WASM-modules direct instantieren:291~292```javascript293const response = await fetch("calculator.wasm");294const { instance } = await WebAssembly.instantiateStreaming(response, {295 env: {296 // Functions the WASM module can call297 log_result: (value) => console.log("Result:", value),298 },299});300~301// Call exported functions302const { add, multiply } = instance.exports;303console.log(add(5, 3)); // 8304console.log(multiply(4, 7)); // 28305```306~307Dit is handig wanneer je minimale overhead wilt en geen rijke type-interop nodig hebt.308~309## Prestaties: WASM vs JavaScript310~311Praktijkbenchmarks tonen significante versnellingen voor CPU-intensieve taken:312~313| Taak | JavaScript | WASM | Versnelling |314|------|-----------|------|---------|315| 4K-beeldverwerking | 180ms | 8ms (met SIMD) | 22x |316| Beeldschaling (4K) | 250ms | 45ms | 5,5x |317| Fysicasimulatie (10K entiteiten) | Framedrops | Vloeiende 60fps | ~10x |318| JSON-parsing (grote payload) | 12ms | 3ms | 4x |319| Cryptografisch hashing | 45ms | 6ms | 7,5x |320~321WASM draait op ongeveer 95% van de native codesnelheid. De grootste winst komt van:322- Voorspelbare prestaties (geen JIT-opwarming, geen GC-pauzes)323- SIMD-instructies voor parallelle dataverwerking324- Directe geheugentoegang zonder garbage collector-interferentie325~326Waar WASM NIET sneller is: DOM-manipulatie, kleine berekeningen, I/O-gebonden taken. JavaScript is hier al voor geoptimaliseerd.327~328## Productietoepassingen329~330### Figma: realtime vectorrendering331~332De 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.333~334### Adobe Photoshop op het web335~336Adobe 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.337~338### Cloudflare Workers339~340Cloudflare 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.341~342### Google Meet343~344Achtergrondvervaging 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.345~346## Browserondersteuning (2026)347~348| Feature | Chrome | Firefox | Safari | Edge |349|---------|--------|---------|--------|------|350| Core WASM | Volledig | Volledig | Volledig | Volledig |351| Threads | Ja | Ja | Ja | Ja |352| SIMD (128-bit) | Ja | Ja | Ja | Ja |353| WasmGC | 119+ | 120+ | 18.2+ | Ja |354| Exception Handling | Ja | Ja | Ja | Ja |355| Memory64 | Ja | Ja | Gedeeltelijk | Ja |356~357Alle grote browsers ondersteunen WASM volledig. De nieuwere features (WasmGC, Exception Handling) zijn breed beschikbaar.358~359## Tooling-referentie360~361| Tool | Doel | Installatie |362|------|---------|---------|363| **wasm-pack** | Rust naar WASM bouwen, npm-pakketten genereren | `cargo install wasm-pack` |364| **wasm-bindgen** | Rust/JS-interop-bindings (gebruikt door wasm-pack) | Dependency in Cargo.toml |365| **wasm-opt** | Optimalisatie van binaire bestandsgrootte (50%+ reductie) | Onderdeel van Binaryen: `brew install binaryen` |366| **wit-bindgen** | Bindings genereren uit WIT-bestanden | `cargo install wit-bindgen-cli` |367| **Wasmtime** | Server-side WASM-runtime (referentie-WASI-implementatie) | `brew install wasmtime` |368| **Wasmer** | Alternatieve WASM-runtime met WASI-ondersteuning | `curl https://get.wasmer.io -sSfL \| sh` |369| **wasm-feature-detect** | Runtime browser-feature-detectie | `npm install wasm-feature-detect` |370~371### Binaire bestandsgrootte optimaliseren372~373WASM-binaries kunnen groot zijn. Zo verklein je ze:374~375```toml376# Cargo.toml377[profile.release]378opt-level = "z" # Optimize for size379lto = true # Link-time optimization380codegen-units = 1 # Better optimization, slower compile381strip = true # Strip debug symbols382```383~384```bash385# Build in release mode386wasm-pack build --release --target web387~388# Further optimize with wasm-opt389wasm-opt -Oz pkg/image_processor_bg.wasm -o pkg/image_processor_bg.wasm390```391~392Een typische Rust-WASM-module gaat van 500KB naar minder dan 50KB met deze optimalisaties.393~394## Startroute395~396```mermaid397flowchart TD398 A[Week 1: Basics] --> B[Week 2: Real Project]399 B --> C[Week 3: WASI and Server-side]400 C --> D[Month 2+: Production]401~402 A --> A1[Install Rust + wasm-pack]403 A --> A2[Build hello-world WASM module]404 A --> A3[Call WASM functions from JavaScript]405~406 B --> B1[Build image processor or game physics]407 B --> B2[Use wasm-bindgen for rich types]408 B --> B3[Benchmark against pure JS]409~410 C --> C1[Run WASM with Wasmtime]411 C --> C2[Explore WASI interfaces]412 C --> C3[Try Component Model with WIT]413~414 D --> D1[Optimize binary size]415 D --> D2[Use SIMD for parallelism]416 D --> D3[Deploy to Cloudflare Workers or browser]417```418~419## Conclusie420~421WebAssembly 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.422~423Je 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.424~425De tooling is volwassen, de browserondersteuning is universeel en het ecosysteem groeit. Als je Rust schrijft, ben je al een commando verwijderd van de browser.426~427> **Startchecklist:**428>429> - [x] Rust en wasm-pack geinstalleerd430> - [x] Eerste WASM-module gebouwd en draaiend in de browser431> - [x] JavaScript-interop werkt (WASM aanroepen vanuit JS)432> - [x] Release-build met grootte-optimalisaties toegepast433> - [x] Prestaties gebenchmarkt tegen puur JavaScript-equivalent434> - [x] WASI verkend met Wasmtime voor server-side toepassingen435~
NORMAL · webassembly-wasm-complete-guide.md [readonly]435 lines · :q to close