WASM : tout savoir sur WebAssembly un standard performant qui enrichit le web

le jeudi 4 février 2021

Bearstech | Dernière mise à jour : jeudi 4 février 2021

Webassembly a su s'imposer comme un standard du web et même en sortir. Il est devenu un incontournable tant pour ses performances que pour l'expérience utilisateurs qu'il offre.

Notre prochain webinar

JS et WASM : une histoire commune

Pour comprendre WebAssembly (aka WASM), une rétrospective de l'histoire de JavaScript est essentielle.

Tout débute en 1995, chez Netscape avec Brendan Eich et la légende qui raconte qu'il aurait écrit les bases du langage en seulement dix jours. Soit, mais c'est en 1996, avec la sortie du navigateur web Netscape 2, que JavaScript se dévoile publiquement. Pourquoi JavaScript d'ailleurs ? Parce que "Java" c'était stylé à l'époque. Netscape a sauté sur l'occasion pour surfer sur la hype en renommant son produit originel LiveScript, en JavaScript à la dernière minute (créant une source de confusion perpétuelle entre le Java et le JavaScript).

Rapidement standardisé via ECMAScript, le langage est utilisé au départ pour valider des formulaires web côté navigateur. Les sites web de plus en plus dirigés vers les interactions avec le client (Web 2.0) démocratisent rapidement JavaScript. Les années passent et le langage se traîne une réputation moyenne, voir carrément catastrophique car les performances varient entre acceptables, médiocres et atroces. Le premier coup de pied dans la fourmillière est donné par Google, en 2008, avec son moteur JavaScript, embarqué dans Google Chrome : V8). L'idée novatrice est de compiler le code JavaScript directement en langage machine, au dernier moment (aka JIT), en l'optimisant au maximum. Le gain en perfomance est tellement impressionant qu'il permet la naissance de nouveaux outils, en particulier Node, qui redore le blason de JavaScript (en l'imposant comme standard pour les outils de build, terminant la guerre Perl/Python/ruby.). En 2012, dans une recherche constante de perfomance, Alon Zakai (Mozilla) travaille sur une idée saugraunue à l'époque : faire tourner du code C dans un navigateur. Pour l'expérience, il crée Emscripten, un outil basé sur CLang et LLVM qui lui permet de compiler du code C vers asm.js (l'ancêtre de WASM). Il s'agit d'un subset de JavaScript orienté performance permettant des optimisations puissantes par des moteurs JavaScript comme V8. En guise de démonstration, Mozilla dévoile, en Mars 2014, des portages de démos de jeux vidéos, basés sur l'Unreal Engine, tournant de manière fluide dans le navigateur et sans plugins (grace à l'intégration de WebGL dans les navigateurs web, un sous ensemble de OpenGL prévu au démarrage pour les smartphones.).

Tous ces travaux et ces expérimentations convergent vers la création du standard WebAssembly (WASM) en 2015. Depuis, les fontionnalités ont été implémentées par les éditeurs de web browsers qui dominent le marché (Chrome, Firefox, Safari, Edge). Ce nouvel outil, standardisé en 2019 par le W3C, promet l'exécution par le navigateur d'un binaire compilé, à des vitesses proches du natif.

WASM, en théorie

WASM n'est pas destiné à être écrit par un humain. Il est plutôt une nouvelle cible de compilation à partir d'un langage source choisi par le développeur. A l'heure actuelle, les outils sont encore nébuleux et les principaux langages permettant d'écrire du code compilable vers WASM sont

  • C/C++ (via Emscripten, l'outil historique)
  • Rust (via un écosystème très complet développé par la communauté)
  • AssemblyScript, inspiré par TypeScript est directement pensé pour WASM
  • Go (via TinyGo et depuis peu, via les outils standards)

Une fois compilé en WASM, le binaire obtenu peut être utilisé directement par le navigateur, indépendamment de la plateforme qui exécute celui-ci (Windows, Linux, macOS, iOS, Android...). Dans ce contexte, les appels à WASM se font via JavaScript et des librairies, généralement fournies par les outils de votre choix.

Le format binaire permet, sans rentrer dans plus de détails, d'imaginer des gains en performance non négligeables. Plus léger qu'un format texte complet (comme peut l'être un fichier JavaScript, même minifié), un fichier WASM sera envoyé plus rapidement via le réseau à l'utilisateur final. A ce premier gain s'ajoute la simplification des étapes de parsing et de compilation (puisque le fichier WASM est déjà compilé en amont), très coûteuses côté client, lors de la réception de fichiers JS.

Embarquant dès la création des notions de sécurité, le code WASM s'éxécute dans le contexte d'une machine virtuelle WebAssembly, sandboxée et contrôlée par le navigateur. Cette isolation sécurise l'environnement WASM en l'obligeant entre autres à passer par l'API JavaScript pour accéder au système de fichiers et au réseau (les concepts sont détaillés dans la documentation).

Wasm, en pratique

Avec ce minimum théorique, on peut maintenant passer à la pratique, avec un inutile mais indispensable Hello World, en WASM.

Pour débuter il faut écrire le code dans un langage source. Go est le candidat parfait pour cet exercice : il compile en WASM depuis l'outil standard et il est utilisé quotidiennement par les Ours.

package main

import "fmt"

func main() {
    fmt.Println("Hello WASM, from GO !")
}

Pour la compilation, il faut simplement spécifier WASM comme architecture de sortie au compilateur :

GOOS=js GOARCH=wasm go build -o hello-wasm.wasm

Une fois le fichier généré, il faut l'utiliser dans une page web.

<html>
    <head>
        <meta charset="utf-8" />
        <title>WASM, Go Hello</title>
        <script src="wasm_exec.js"></script>
        <script>
            const gowasm = new Go();
            WebAssembly.instantiateStreaming(fetch("./hello-wasm.wasm"), gowasm.importObject).then((result) => {
                gowasm.run(result.instance);
            });
        </script>
    </head>
    <body></body>
</html>

L'interface entre le code WASM et le le JS de la page est facilité par la librairie wasm_exec.js fournie par Golang. Après avoir récupéré le fichier WebAssembly via un appel à fetch, l'objet est instancié, la machine virtuelle WASM est initialisée et la fonction mise à disposition par le code WASM est appelée.

Pour tester simplement, rien de mieux qu'un python3 -m http.server !

En accédant à la page via un navigateur web moderne et en lorgnant sur l'inspecteur, dans l'onglet réseau le fichier WASM pointe le bout de son nez :

Inspection réseau, visualisation du fichier WASM

Pour terminer, l'onglet console nous affiche le message Hello WASM, from GO !. Objectif atteint ! Le Hello World crée avec Go, s'exécute dans le navigateur, via WASM 👏 !

Inspection console, visualisation du message via une fonction WASM

Vers le Web et au-delà !

Alors c'est certain, un Hello World ça permet la découverte mais qu'est-ce qu'on peut bien faire avec WASM, dans la vraie vie ?

Chose essentielle : WebAssembly est un outil complémentaire a l'écosystème existant (HTML, CSS, JavaScript). Son but n'est pas de remplacer JavaScript (même si certains expérimentent dans cette direction) mais de le compléter pour des tâches annexes avec un fort besoin en performances. Cet aspect modulaire permet une adpotion incrémentale et fluide de la technologie en remplaçant petit à petit les domaines où le JS n'est pas performant. En guise d'illustration, des processus de traitement du son ou de l'image sont parfaitement adaptés à des librairies écrites et testées en Rust. Le développeur a ainsi accès à l'ensemble des outils (du Langage Server pour son éditeur, aux librairies et la gestion des dépendances en passant par les tests unitaires) du langage source choisi. Dans cet environement familier. Il développe du code qui, une fois compilé vers WASM, s'utilisera dans le navigateur via JavaScript avec des performances proches du natif. Les domaines d'application sont assez larges et vont de la 3D à l'IA, en passant par le traitment du son, de l'image ou encore les jeux vidéos. Les usages sont nombreux et la démonstration la plus WOW effect est probablement la version web du logiciel AutoCad qui utilise intensivement WASM.

Dans la version actuelle de la spécification, la notion de DOM n'est même pas évoquée. Ce détail a son importance car il fait de WebAssembly un outil générique qui s'étend au-delà du web et du navigateur. A la manière de Node pour JavaScript, des runtimes web assembly sont développés dans le but d'éxécuter du code WASM côté serveur. Wasmer, par exemple, est celui qui buzz en ce moment. In fine, de tels outils permettent de créer des binaires légers, partageables facilement et exécutables dans un environement isolé (appeler ça des microconteneurs n'est même pas déconnant). Pour éviter l'effet foire à la saucisse d'implémentations, Mozilla a rapidement travaillé sur une interface commune : WASI afin d'harmoniser les accès au système de fichiers et au réseau (Wasmer, utilise WASI). Une telle harmonisation du runtime est un véritable cadeau pour les fournisseurs de services. Imaginez, à terme, un service FAAS ou les clients écrivent du code dans le langage de leur choix, compilé en WASM et exécuté sur les serveurs dans un runtime WebAssembly : le pied.

Attention tout de même, la peinture est encore fraîche et certaines fonctionnalités ne sont pas encore implémentées. La notion de garbage collector est pour le moment en discussion. C'est pourquoi, les langages les plus populaires pour compiler vers WASM sont ceux où la gestion de la mémoire se fait à la mimine (Rust, C/C++). L'autre gros sujet dans les tuyaux est la concurrence et le multithreading : de quoi proposer des performances inégalées et des usages nouveaux dans le navigateur et au-delà.

Pour conclure, tout porte à croire que WASM est une technologie à suivre avec intêret, tant les promesses sont alléchantes et illustrées par des exemples concrets dans des applications de plus en plus nombreuses et variées.

Service Conseil et accompagnement docker

Bearstech vous propose ses services Conseil et accompagnement docker

Découvrir ce service

Partager cet article

Flux RSS

flux rss

Partager cet article :