WebAssembly (WASM) e nato come un modo per eseguire C++ nel browser. Nel 2026, gira ovunque - browser, server, reti edge, dispositivi embedded - e alimenta alcune delle applicazioni piu impegnative del web. Il motore di rendering di Figma, Adobe Photoshop sul web, l'elaborazione video di Google Meet e la piattaforma di calcolo edge di Cloudflare funzionano tutti su WebAssembly.
Chrome Platform Status colloca WASM a circa il 5,5% di tutti i caricamenti di pagina su Chrome all'inizio del 2026, in crescita rispetto al 4,5% dell'anno precedente. Con WASM 3.0 diventato standard W3C e WASI in fase di maturazione verso la versione 1.0, l'ecosistema ha raggiunto un punto di svolta.
Questa guida copre tutto cio che devi sapere per iniziare a sviluppare con WebAssembly.
Cos'e WebAssembly?
WebAssembly e un formato di istruzioni binarie progettato come target di compilazione. Scrivi il codice in un linguaggio ad alto livello (Rust, C, C++, Go, Kotlin), lo compili in .wasm e lo esegui in qualsiasi ambiente che disponga di un runtime WASM - browser, Node.js, Cloudflare Workers, Wasmtime o Wasmer.
Come funziona
WASM e una macchina virtuale basata su stack. Le funzioni inseriscono e rimuovono valori da uno stack di operandi. Il runtime host (V8 in Chrome, SpiderMonkey in Firefox) compila JIT il bytecode WASM in codice macchina nativo, ed e per questo che le prestazioni sono quasi native.
Caratteristiche principali:
- Esecuzione in sandbox: i moduli WASM possono accedere solo alle risorse che l'host concede esplicitamente. Nessun accesso al filesystem, alla rete o al sistema operativo a meno che non sia permesso. Questo e fondamentalmente diverso dal codice nativo.
- Memoria lineare: un singolo
ArrayBuffercontiguo condiviso tra WASM e l'host. I dati complessi (stringhe, struct) vengono passati scrivendo in memoria e condividendo un puntatore. - Tipi limitati: WASM supporta nativamente solo quattro tipi:
i32,i64,f32,f64. Tutto il resto (stringhe, array, oggetti) richiede la codifica attraverso la memoria lineare o il Component Model. - Portabile: lo stesso binario
.wasmgira su qualsiasi piattaforma con un runtime WASM, senza ricompilazione.
WASM vs JavaScript
WASM non sostituisce JavaScript. Lo complementa.
| Aspetto | JavaScript | WebAssembly |
|---|---|---|
| Parsing | Parsing + compilazione a runtime | Binario pre-compilato, solo decodifica |
| Velocita di esecuzione | Ottimizzato JIT, variabile | Quasi nativo, costante |
| Avvio | Veloce per piccoli script | Decodifica veloce, prevedibile |
| Accesso al DOM | Diretto | Indiretto (tramite glue JS) |
| Ideale per | UI, manipolazione DOM, gestione eventi | Calcolo intensivo sulla CPU |
| Garbage collection | Integrato | WasmGC (nuovo), o manuale |
Usa JavaScript per l'interfaccia utente e il lavoro sul DOM. Usa WASM per il calcolo pesante: elaborazione immagini, codifica video, simulazioni fisiche, crittografia, parsing di dati.
WASM 3.0: le novita
WebAssembly 3.0 e diventato standard W3C nel settembre 2025, standardizzando nove funzionalita che erano in fase di sviluppo da anni.
| Funzionalita | Cosa abilita |
|---|---|
| WasmGC | Garbage collection nativa in WASM. I linguaggi gestiti (Java, Kotlin, Dart) possono compilare in WASM senza includere il proprio runtime GC. Supportato in Chrome 119+, Firefox 120+, Safari 18.2+. |
| Exception Handling | try/catch nativi in WASM. In precedenza, le eccezioni richiedevano costosi roundtrip verso JavaScript. |
| Tail Calls | Abilita la ricorsione efficiente senza stack overflow. Fondamentale per i linguaggi funzionali. |
| Relaxed SIMD | Istruzioni vettoriali a 128 bit per l'elaborazione parallela dei dati. Abilita ottimizzazioni specifiche per l'hardware. |
| Memory64 | Supera il limite di 4GB di memoria lineare. Necessario per l'elaborazione di dati su larga scala. |
| Multi-memory | Piu regioni di memoria indipendenti in un singolo modulo. |
La piu impattante e WasmGC. Prima di essa, compilare Java o Kotlin in WASM significava includere un intero garbage collector come parte del binario, gonfiando le dimensioni del file. Ora il GC del browser gestisce la memoria per i moduli WASM, esattamente come fa per JavaScript.
WASI: WebAssembly oltre il browser
WASM nel browser e potente, ma WASI (WebAssembly System Interface) e cio che rende WASM un runtime universale. WASI fornisce interfacce standardizzate per le risorse di sistema - file, rete, orologi, numeri casuali - permettendo ai moduli WASM di funzionare al di fuori del browser.
WASI Preview 2 (l'attuale release stabile) definisce queste interfacce:
wasi:filesystem- operazioni sui file tramite handle di capacita (non i tradizionali file descriptor)wasi:sockets- networking TCP/UDPwasi:http- gestione richieste/risposte HTTPwasi:clocks- orologio di sistema, orologio monotonicowasi:random- casualita crittograficawasi:cli- argomenti della riga di comando, variabili d'ambiente, stdio
Il principio chiave e la sicurezza basata sulle capacita: un modulo WASM non puo accedere al filesystem a meno che l'host non conceda esplicitamente un handle a una directory specifica. Questo rende WASI fondamentalmente piu sicuro rispetto all'esecuzione di eseguibili nativi.
Il percorso verso WASI 1.0
WASI 0.3.0 (che aggiunge primitive async/concorrenza) e previsto nel 2026, con WASI 1.0 a seguire. L'aggiunta principale e l'async integrato nel linguaggio con I/O streaming a copia zero.
Il Component Model
I moduli WASM di base possono scambiare solo numeri. Il Component Model risolve questa limitazione aggiungendo un sistema di tipi ricco e un livello di composabilita sopra WASM.
WIT (WebAssembly Interface Types)
WIT e un linguaggio di definizione delle interfacce che permette ai componenti di dichiarare le proprie importazioni ed esportazioni con tipi ricchi - stringhe, record, liste, varianti, enum - non solo i32 e 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; }
Le toolchain come wit-bindgen generano binding specifici per il linguaggio a partire dai file WIT. Un componente Rust e un componente Python possono scambiare stringhe, record e liste attraverso contratti WIT senza che nessuna delle due parti conosca il linguaggio di implementazione dell'altra.
Costruire il tuo primo modulo WASM con Rust
Rust ha gli strumenti WASM piu maturi. Costruiamo un esempio pratico: un modulo di elaborazione immagini che gira nel browser.
Configurazione
# 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
Configurare Cargo.toml
[package] name = "image-processor" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2"
Scrivere il codice Rust
// 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
Questo produce una directory pkg/ con:
image_processor_bg.wasm- il binario WASM compilatoimage_processor.js- codice glue JavaScript con definizioni TypeScriptpackage.json- pronto per la pubblicazione su npm
Utilizzo 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>
Il punto chiave: imageData.data e un Uint8ClampedArray supportato da un ArrayBuffer. Quando viene passato a WASM, condivide la stessa memoria - nessuna copia. La funzione Rust modifica i pixel direttamente, e il lato JavaScript vede immediatamente le modifiche.
Livello piu basso: istanziazione manuale di WASM
Se non vuoi usare wasm-bindgen, puoi istanziare direttamente i moduli WASM:
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
Questo e utile quando si vuole un overhead minimo e non si ha bisogno di interoperabilita avanzata tra tipi.
Prestazioni: WASM vs JavaScript
I benchmark reali mostrano accelerazioni significative per i compiti intensivi sulla CPU:
| Compito | JavaScript | WASM | Accelerazione |
|---|---|---|---|
| Elaborazione immagine 4K | 180ms | 8ms (con SIMD) | 22x |
| Ridimensionamento immagine (4K) | 250ms | 45ms | 5,5x |
| Simulazione fisica (10K entita) | Frame persi | 60fps fluidi | ~10x |
| Parsing JSON (payload grande) | 12ms | 3ms | 4x |
| Hashing crittografico | 45ms | 6ms | 7,5x |
WASM gira a circa il 95% della velocita del codice nativo. I maggiori guadagni derivano da:
- Prestazioni prevedibili (nessun warmup JIT, nessuna pausa del GC)
- Istruzioni SIMD per l'elaborazione parallela dei dati
- Accesso diretto alla memoria senza interferenza del garbage collector
Dove WASM NON e piu veloce: manipolazione del DOM, piccoli calcoli, compiti legati all'I/O. JavaScript e gia ottimizzato per questi casi.
Casi d'uso in produzione
Figma: rendering vettoriale in tempo reale
Il motore di rendering principale di Figma e C++ compilato in WASM. Ogni forma, gradiente ed effetto viene calcolato in WASM e disegnato su un elemento Canvas. Questo permette a Figma di gestire design complessi con migliaia di livelli a 60fps nel browser - prestazioni impossibili in puro JavaScript.
Adobe Photoshop sul web
Adobe ha portato filtri e strumenti chiave di Photoshop in WASM utilizzando Rust. I loro benchmark mostrano l'elaborazione di immagini 4K in 22ms con WASM SIMD contro 180ms in JavaScript - un miglioramento di 8 volte che rende possibili le anteprime dei filtri in tempo reale.
Cloudflare Workers
Cloudflare esegue moduli WASM in isolati V8 in oltre 330 posizioni edge. I cold start sono di 1-5ms (rispetto ai 100-500ms per il serverless basato su container). A febbraio 2026, hanno distribuito l'inferenza di Llama-3-8b attraverso la loro rete edge utilizzando WASM.
Google Meet
La sfocatura dello sfondo e gli sfondi virtuali in Google Meet utilizzano WASM con SIMD per l'elaborazione video in tempo reale. Il modulo WASM elabora ogni frame video abbastanza velocemente da mantenere un video fluido a 30fps.
Supporto browser (2026)
| Funzionalita | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Core WASM | Completo | Completo | Completo | Completo |
| Threads | Si | Si | Si | Si |
| SIMD (128 bit) | Si | Si | Si | Si |
| WasmGC | 119+ | 120+ | 18.2+ | Si |
| Exception Handling | Si | Si | Si | Si |
| Memory64 | Si | Si | Parziale | Si |
Tutti i principali browser supportano pienamente WASM. Le funzionalita piu recenti (WasmGC, Exception Handling) hanno raggiunto un'ampia disponibilita.
Riferimento degli strumenti
| Strumento | Scopo | Installazione |
|---|---|---|
| wasm-pack | Compilare Rust in WASM, generare pacchetti npm | cargo install wasm-pack |
| wasm-bindgen | Binding di interoperabilita Rust/JS (usato da wasm-pack) | Dipendenza nel Cargo.toml |
| wasm-opt | Ottimizzazione delle dimensioni del binario (riduzione del 50%+) | Parte di Binaryen: brew install binaryen |
| wit-bindgen | Generare binding dai file WIT | cargo install wit-bindgen-cli |
| Wasmtime | Runtime WASM lato server (implementazione di riferimento WASI) | brew install wasmtime |
| Wasmer | Runtime WASM alternativo con supporto WASI | curl https://get.wasmer.io -sSfL | sh |
| wasm-feature-detect | Rilevamento delle funzionalita del browser a runtime | npm install wasm-feature-detect |
Ottimizzare le dimensioni del binario
I binari WASM possono essere grandi. Ecco come ridurli:
# 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
Un tipico modulo WASM in Rust passa da 500KB a meno di 50KB con queste ottimizzazioni.
Percorso per iniziare
Conclusione
WebAssembly non e piu sperimentale. E una tecnologia di produzione utilizzata da alcune delle applicazioni piu impegnative del web. Prestazioni quasi native, sicurezza in sandbox e portabilita universale - nessun altro target di compilazione ti offre tutte e tre queste caratteristiche.
Non devi riscrivere l'intera applicazione in WASM. Inizia con una singola funzione intensiva sulla CPU - un filtro per immagini, un parser di dati, un calcolo fisico - compilala in WASM e chiamala da JavaScript. Misura la differenza. Poi decidi dove altro WASM puo essere d'aiuto.
Gli strumenti sono maturi, il supporto dei browser e universale e l'ecosistema sta crescendo. Se scrivi in Rust, sei gia a un comando di distanza dal browser.
Checklist per iniziare:
- Rust e wasm-pack installati
- Primo modulo WASM compilato e funzionante nel browser
- Interoperabilita JavaScript funzionante (chiamare WASM da JS)
- Build di rilascio con ottimizzazioni delle dimensioni applicate
- Prestazioni confrontate con l'equivalente in puro JavaScript
- WASI esplorato con Wasmtime per i casi d'uso lato server