WebAssembly (Wasm) promet des performances natives dans le navigateur. Après l’avoir utilisé en production sur plusieurs projets, voici ce qui fonctionne vraiment et ce qui relève du marketing.

WebAssembly en 2 minutes

Qu’est-ce que c’est ?

WebAssembly est un format binaire exécutable dans les navigateurs modernes, offrant des performances proches du code natif.

┌─────────────┐
│ Rust/C/C++  │
│ Go, etc.    │
└──────┬──────┘
       │ Compile
┌──────▼──────┐
│   .wasm     │ ← Binaire compact
└──────┬──────┘
       │ Load
┌──────▼──────┐
│  Browser    │ ← Exécution rapide
└─────────────┘

Promesses marketing vs Réalité

Marketing : “Wasm est 20x plus rapide que JavaScript !”

Réalité : Dépend totalement du cas d’usage.

Cas d’usage où Wasm excelle

1. Calculs intensifs

Exemple : Traitement d’image

// Rust compilé en Wasm
#[wasm_bindgen]
pub fn apply_filter(pixels: &mut [u8], width: u32, height: u32) {
    for y in 0..height {
        for x in 0..width {
            let idx = (y * width + x) * 4;
            // Algorithme gourmand en CPU
            pixels[idx] = compute_pixel(pixels[idx]);
        }
    }
}

Résultat mesuré :

  • JavaScript : 450ms
  • Wasm : 85ms
  • Gain : 5.3x

2. Portage d’applications existantes

Cas réel : Porter un éditeur vidéo C++ vers le web.

Avant :

  • Réécrire en JavaScript : 6 mois + bugs
  • Performance dégradée

Avec Wasm :

  • Compilation directe : 2 semaines
  • Performance proche du natif
  • Code existant réutilisé

Exemples célèbres :

  • Figma (éditeur graphique)
  • AutoCAD Web
  • Google Earth

3. Bibliothèques de compression

// Bibliothèque de compression Wasm
import { compress } from './wasm-compress';

// 3x plus rapide que zlib JavaScript
const compressed = await compress(largeData);

Use cases :

  • Compression vidéo/audio
  • Encodage/décodage images
  • Cryptographie

Quand NE PAS utiliser Wasm

1. DOM manipulation

// ❌ Wasm n'a pas accès direct au DOM
// Doit passer par JavaScript (overhead)

// JavaScript reste KING pour ça :
document.querySelector('.button').addEventListener('click', () => {
  // Wasm serait plus lent ici !
});

2. Applications “business logic” simples

// ❌ Pas besoin de Wasm pour ça
function calculateTotal(items) {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// JavaScript est amplement suffisant

3. I/O intensive

Wasm n’accélère pas :

  • Requêtes HTTP
  • Accès BDD
  • Lecture fichiers

Le bottleneck est ailleurs.

Performance : Benchmarks réels

Test 1 : Calcul Fibonacci (CPU-bound)

// JavaScript
function fib(n) {
  if (n <= 1) return n;
  return fib(n - 1) + fib(n - 2);
}

// Résultats fib(40) :
// JavaScript : 1250ms
// Wasm : 680ms
// Gain : 1.8x

Test 2 : Parsing JSON (I/O-bound)

// Résultats parsing 10MB JSON :
// JavaScript : 85ms
// Wasm : 82ms
// Gain : 1.04x (négligeable)

Conclusion : Wasm brille sur CPU-bound, pas I/O-bound.

Stack technique : Rust → Wasm

Setup projet

# Installer wasm-pack
cargo install wasm-pack

# Créer projet
cargo new --lib my-wasm-lib
cd my-wasm-lib

Code Rust

// src/lib.rs
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn heavy_computation(data: Vec<u8>) -> Vec<u8> {
    // Traitement intensif
    data.iter()
        .map(|&x| complex_algo(x))
        .collect()
}

fn complex_algo(n: u8) -> u8 {
    // Algorithme coûteux
    (0..n).fold(0, |acc, x| acc ^ x)
}

Build et intégration

# Compiler en Wasm
wasm-pack build --target web

# Génère :
# pkg/
#   my_wasm_lib_bg.wasm
#   my_wasm_lib.js
// app.js
import init, { heavy_computation } from './pkg/my_wasm_lib.js';

async function main() {
  await init();  // Charger le module Wasm

  const data = new Uint8Array([1, 2, 3, 4, 5]);
  const result = heavy_computation(data);

  console.log(result);
}

main();

Optimisation : Taille bundle

Problème : Wasm peut être lourd

my_wasm_lib_bg.wasm : 287KB
my_wasm_lib.js : 12KB
Total : 299KB

Optimisation 1 : wasm-opt

# Installer binaryen
npm install -g binaryen

# Optimiser
wasm-opt -Oz -o optimized.wasm input.wasm

# Résultat : 287KB → 156KB (-45%)

Optimisation 2 : Lazy loading

// Ne charger Wasm que si nécessaire
button.addEventListener('click', async () => {
  const { heavy_computation } = await import('./pkg/my_wasm_lib.js');
  // Wasm chargé seulement au clic
});

Optimisation 3 : Streaming compilation

// Compilation en streaming (plus rapide)
const { instance } = await WebAssembly.instantiateStreaming(
  fetch('optimized.wasm')
);

Production : Nos retours d’expérience

Projet 1 : Éditeur de PDF web

Contexte :

  • Manipulation PDF côté client
  • Rotation, fusion, compression pages

Stack :

  • Rust + pdf-rs
  • Compilé en Wasm

Résultats :

  • Fusion 10 PDFs (50 pages) : 2.1s (vs impossible en JS pur)
  • Bundle Wasm : 1.2MB (gzipped)
  • Satisfaction users : 9.2/10

Projet 2 : Plateforme e-learning

Contexte :

  • Détection plagiat côté client
  • Algorithme Levenshtein distance sur gros textes

Stack :

  • AssemblyScript → Wasm

Résultats :

  • Comparaison 2000 mots : 145ms (vs 890ms JS)
  • Gain : 6.1x
  • ROI dev : 2 semaines

Debugging Wasm : Les outils

1. Chrome DevTools

Sources → WebAssembly
- Voir le bytecode Wasm
- Breakpoints
- Call stack

2. wasm-sourcemap

# Générer sourcemaps
wasm-pack build --debug

# Debugger le code Rust dans Chrome !

3. Console logging

// Rust
use web_sys::console;

#[wasm_bindgen]
pub fn debug_func() {
    console::log_1(&"Debug from Wasm!".into());
}

Futur : Wasm Component Model

Ce qui arrive en 2025-2026 :

Component Model : Wasm modules composables
- Interopérabilité entre langages
- Standard d'import/export
- Écosystème de composants réutilisables

Exemple (futur) :

// Composer modules Wasm de différentes sources
import { image_filter } from 'wasm:image-processing';
import { compress } from 'wasm:compression';

const filtered = image_filter(image);
const compressed = compress(filtered);

Checklist décision

Utilisez Wasm si :

✅ Calculs CPU-intensifs (>100ms en JS) ✅ Portage code existant (C/C++/Rust) ✅ Performance critique mesurée ✅ Bibliothèque spécialisée disponible

Restez sur JavaScript si :

❌ DOM manipulation ❌ I/O-bound (HTTP, DB) ❌ Logique métier simple ❌ Pas de besoin perf critique

Ressources

Outils

Learning

Conclusion

WebAssembly n’est pas un remplacement de JavaScript.

C’est un complément pour des cas d’usage spécifiques :

  • Calculs intensifs
  • Portage d’applications
  • Performance critique

Approche pragmatique :

  1. Mesurer le problème réel
  2. Tester avec Wasm sur un POC
  3. Comparer les métriques
  4. Décider avec data

En 2025, Wasm est mature pour la production. Mais utilisez-le uniquement quand il apporte une vraie valeur.

Et vous, avez-vous des use cases Wasm ? Partagez !