- Depuis son lancement initial en 2017, WebAssembly a progressé en prenant en charge l’exécution de langages bas niveau comme C/C++, mais il est toujours traité comme un langage de seconde zone sur la plateforme Web
- Seul JavaScript peut interagir directement avec les API Web, et WebAssembly doit pour cela s’appuyer sur un code de liaison JS complexe (glue code)
- Cette structure entraîne une procédure de chargement complexe, un surcoût de performance et une rupture des toolchains selon les langages, ce qui dégrade l’expérience développeur
- Pour résoudre ce problème, Mozilla propose le WebAssembly Component Model, qui permet d’appeler les API Web et de charger des modules de manière standardisée sans JavaScript
- Si ce modèle s’impose, WebAssembly pourrait devenir un environnement d’exécution de première classe dans le navigateur, ouvrant la voie à une adoption plus simple par les développeurs généralistes
Pourquoi WebAssembly est traité comme un langage de seconde zone
- WebAssembly ne peut accéder à la plateforme Web qu’à travers JavaScript, sans droit d’appel direct aux API Web
- JavaScript se charge simplement via une balise
<script>, alors que WebAssembly nécessite un processus de chargement manuel via l’API JS
- Il faut passer par des appels d’API complexes comme
WebAssembly.instantiateStreaming(), que les développeurs doivent mémoriser ou automatiser via des outils
- La proposition esm-integration simplifie ce chargement en permettant d’importer directement des fichiers
.wasm via le système de modules JS
- Chargement direct possible sous la forme
<script type="module" src="/module.wasm"></script>
Les limites d’accès aux API Web
- Là où une simple ligne
console.log("hello, world") suffit en JavaScript, WebAssembly exige une procédure complexe impliquant accès à la mémoire JS, décodage de chaînes et encapsulation de fonctions
- WebAssembly ne peut ni accéder à l’objet
console ni au DOM ; il doit donc passer par des appels indirects via partage mémoire et import/export de fonctions côté JS
- Le code de liaison (glue code) généré dans ce processus diffère selon les langages et est produit automatiquement par des outils comme
embind ou wasm-bindgen
- Mais cela entraîne une plus grande complexité de build, un surcoût à l’exécution et des incompatibilités entre langages
Les causes techniques qui empêchent WebAssembly de devenir un langage de première classe
- Difficulté d’intégration des compilateurs : le compilateur de chaque langage doit générer séparément le code d’intégration avec JS et la plateforme Web, ce qui n’est pas réutilisable
- Incompatibilité des compilateurs standards : un fichier généré avec
rustc --target=wasm ne s’exécute pas directement dans le navigateur
- Il faut installer séparément une toolchain non officielle qui implémente l’intégration à la plateforme
- Biais de l’écosystème documentaire : la documentation Web, comme MDN, est majoritairement centrée sur JavaScript, ce qui élève la barrière d’entrée pour les utilisateurs d’autres langages
- Problèmes de performance : les appels DOM passant par des liaisons JS subissent une baisse de performance de 45 % par rapport aux appels directs
- Dans les expérimentations du framework Dodrio, supprimer le glue code JS a réduit de moitié le temps d’application des modifications du DOM
- Dépendance à JavaScript : pour utiliser WebAssembly en production, il faut au final comprendre JS, ce qui mène à un problème de leaky abstraction
L’arrivée du WebAssembly Component Model
- Le WebAssembly Component Model définit une unité d’exécution standardisée utilisable en commun par plusieurs langages et runtimes
- Il permet d’effectuer directement l’accès aux API Web, le chargement des modules et l’édition de liens, sans JavaScript
- Il peut être généré par différents langages et exécuté dans divers runtimes, comme les navigateurs ou Wasmtime
- Grâce à WIT (Interface Description Language), il est possible de déclarer les API nécessaires et de les appeler directement depuis le composant
- Le navigateur peut charger directement un composant via
<script type="module" src="component.wasm"></script>, avec gestion automatique des liaisons aux API Web sans JS
Interopérabilité avec JavaScript
- Le Component Model prend aussi en charge une architecture d’application hybride
- Exemple : écrire un décodeur d’image en WebAssembly, puis l’appeler depuis JS sous la forme
import { Image } from "image-lib.wasm";
- JS peut utiliser les composants WebAssembly via import/export comme s’il s’agissait de modules ordinaires
Perspectives et participation
- Mozilla collabore avec le WebAssembly CG sur la standardisation du Component Model, et Google est également en phase d’examen
- Les développeurs peuvent expérimenter via Jco ou Wasmtime dans le navigateur ou en CLI
- Si ce modèle s’impose, WebAssembly pourrait passer d’une fonctionnalité réservée aux power users à une technologie Web accessible aux développeurs généralistes
4 commentaires
C’est tout simplement plus proche d’un vœu pieux à la Mozilla. Le front-end ne peut pas, structurellement, échapper au système limbique de la réaction du marché. Dès l’apparition de WebAssembly, Doom 3 a été porté. Le DOM est depuis longtemps devenu un objet proxy léger dans les navigateurs modernes et, si l’on prend en compte le jeu d’instructions dédié à JavaScript des CPU modernes ainsi que les limites quasi quantiques du mono-cœur, une telle approche ne prendra jamais durablement l’avantage en termes de valeur de marché.
Quel sens cela a-t-il d’avoir un binaire WebAssembly qui tourne dans Electron ? On dirait simplement une nouvelle variante de GitKraken CLI, ou une chasse à la réputation via un portage Rust.
Sans parler du reste, l’idée d’insérer un module wasm comme fichier, à la manière de
<script type="module" src="/module.wasm"></script>, me paraît franchement séduisante.Et il faut bien dire que les affirmations selon lesquelles WebAssembly aurait une barrière à l’entrée élevée sont absurdes. C’est simplement que la nécessité de le faire est moindre que la volonté de payer. Vous voulez de la rapidité et une faible empreinte tout en utilisant le DOM et le CSS ? C’est quoi, cette comédie noire ?
Avis Hacker News
C’est dommage qu’on n’ait pas considéré l’absence d’accès au DOM comme un problème lorsqu’on a abandonné l’objectif initial de prendre en charge WebIDL dans WebAssembly pour créer un autre IDL
Bien sûr, je comprends la réalité du marché, mais je n’arrive pas à me défaire de l’idée du temps perdu
Liens de référence : historique du commit, rétrospective sur stringref, article de l’ACM
Deux objectifs supplémentaires ont ensuite été ajoutés : la prise en charge des API non web et l’interopérabilité entre langages
WebIDL est l’union de JS et des Web API, donc son expressivité est élevée, mais il contient beaucoup de concepts en conflit avec ces objectifs
C’est pourquoi l’interface des composants a choisi une approche par intersection beaucoup plus portable, avec moins d’expressivité
Personnellement, je pense que l’accès au DOM est important, mais le Wasm CG était occupé par des priorités plus urgentes
Si j’ai écrit cet article, c’est pour faire savoir que je me souviens toujours de ce problème et que je compte continuer à travailler dessus
La toolchain et le processus de build sont tellement complexes que je ressens une charge cognitive chaque fois que je l’utilise
Les performances sont bien meilleures sans glue, mais cela augmente aussi les facteurs de risque
J’espère que le modèle de composants n’introduira pas une nouvelle couche de complexité, mais les exemples dans plusieurs langages semblent déjà assez confus
En particulier, quand on regarde l’exemple Go, il y a trop de fichiers générés et, du point de vue du développeur, une simplification du tooling est indispensable
Pour l’instant, on a l’impression qu’on ne supprime pas la complexité, on la déplace simplement
La spécification wasm component a beaucoup évolué, ce qui a entraîné beaucoup de churn
L’objectif est que les développeurs web n’aient pas à écrire eux-mêmes du WIT et puissent utiliser les Web API comme une bibliothèque
Mais il reste encore beaucoup de chemin à parcourir
Par exemple, si on séparait le partage de texte, le partage de médias et le partage d’applications, la sécurité s’en trouverait améliorée et de petites équipes pourraient créer des alternatives aux navigateurs
Mais l’ampleur gigantesque des Web API et de CSS semble soutenir le monopole des navigateurs, donc ce genre de tentative paraît difficile
Ce serait bien de standardiser un registre WebAssembly pour permettre d’assembler facilement des composants
Au fond, le web est un processus de définition d’un système d’exploitation distribué
C’est bien structuré, des concepts jusqu’aux exemples de code
Dans l’écosystème JS, les trois projets clés sont StarlingMonkey, ComponentizeJS et jco
Aujourd’hui, la toolchain la plus mature est celle de Rust, mais le support des langages basés sur LLVM (C/C++, Go, Python, etc.) s’améliore progressivement
L’objectif de WebAssembly est de devenir une cible de compilation intégrée naturellement aux toolchains locales
Tant qu’il faut encore comprendre du code glue spécifique à chaque langage ou deux modèles d’exécution, WebAssembly restera un « outil réservé aux situations extrêmes »
Pour provoquer un vrai changement, il faut simplifier le chemin de build standard
On ne voit pas clairement comment cela est géré dans le Component Model
Le DOM diffère selon les navigateurs, et les fonctionnalités changent à chaque chargement de page
Dans une couche de pont JS, on peut facilement appliquer des polyfills, mais avec une interface WIT, la détection de méthodes à l’exécution ou les polyfills sont difficiles
Au-delà des performances, la souplesse de l’écosystème compte aussi
Le fait de gérer soi-même du code glue JS ou de dépendre d’outils de génération automatique donne l’impression d’une grande régression
Le fait que l’expérience Dodrio ait permis une réduction de 45 % du surcoût en supprimant le glue est impressionnant
En revanche, je me demande comment se passe la gestion mémoire quand le WebAssembly Component Model interagit directement avec les Web API
J’aimerais savoir si la proposition Wasm GC est utilisée pour conserver les références DOM, ou si cela dépend toujours du GC de JS
J’attends avec impatience que Wasm devienne un véritable citoyen de première classe
Mais actuellement, l’IPC reste inefficace, et je pense qu’il faudrait quelque chose comme des transferts par pages mémoire
Permettre à n’importe qui d’exécuter des programmes complexes sur mon ordinateur était une idée folle du point de vue de la sécurité, mais c’est pourtant ce que nous avons fait
Grâce à JS, nous avons subi d’innombrables failles de sécurité navigateur pendant 20 ans, mais nous avons maintenant des principes de conception et des mesures d’atténuation bien établis
Et voilà qu’on essaie maintenant de remplacer cela par un autre paradigme d’exécution risqué, ce qui est à la fois ironique et beau
Les OS mobiles y parviennent bien mieux que les ordinateurs de bureau
Ils sont conçus du point de vue des ingénieurs, sans workflow par défaut convivial pour les auteurs
Heureusement, il reste des gens qui se préoccupent de ce problème
On a l’impression d’un excès d’ingénierie pour un traitement des chaînes 2x plus rapide, juste pour mapper les API DOM en 1:1
Avec des API comme WebGL2, WebGPU ou WebAudio, le coût d’un shim JS est déjà négligeable
Le vrai problème se situe dans des éléments comme la copie de buffers GPU, et le component model n’aide pas sur ce point
J’aimerais voir des benchmarks testant des dizaines de milliers de draw calls sur WebGL2 ou WebGPU
Au-delà des performances, l’amélioration de l’expérience développeur (DX) est importante
Aujourd’hui, démarrer est trop difficile, et tout le monde doit devenir expert pour en tirer un bénéfice
S’il peut rivaliser avec l’efficacité des applications natives, ce serait une évolution porteuse d’une vraie vision pour l’avenir du web
À l’ère des agents de codage, les améliorations de DX qu’ils mettent en avant n’ont plus vraiment d’importance