Comprendre WebAssembly en 5 minutes
WebAssembly a rejoint le HTML, CSS et Javascript en tant que standard du web le 5 décembre 2019. Ça va être utile pour beaucoup de choses et au niveau performances, c’est du jamais vu dans un navigateur. Si t’as cinq minutes devant toi, il faut que je t’explique la petite révolution en cours.
Il était une fois
En 1995, Javascript était créé en l’espace de 10 jours par Brendan Eich. Et à ce moment précis, Javascript c’était pas du tout désigné pour être rapide. Sortie de la validation de formulaires c’est l’enfer comme c’est lent. Au fur et à mesure du temps ça s’arrangeait, mais à cette époque, Javascript jouait avec son caca côté performance.
En 2008, Google est sorti de nulle part et a posé sur la table son nouveau navigateur : Google Chrome. À l’intérieur de Chrome se trouvait un moteur Javascript appelé V8. Et la révolution de V8 c’était la compilation Just in Time (JIT) du Javascript. Ce changement de code interprété à la compilation JIT accélérait monstrueusement les performances de Javascript, et donc des navigateurs de façon générale. Cette vitesse allait permettre la naissance de technologie comme NodeJS ou Électron et l’explosion de popularité de Javascript.
En 2015, WebAssembly est pour la première fois annoncé avec une petite démo d’un jeu qui tourne sous Unity. Le jeu tourne directement dans le navigateur !
En 2019, la W3C faisait de WebAssembly une nouvelle norme du web. Comme l’a été le moteur V8 à son époque, WebAssembly s’annonce comme la nouvelle révolution coté performance. WebAssembly est donc déjà là, et son top départ a été fulgurant.
C’est quoi WebAssembly ?
WebAssembly, abrégé en wasm, est une façon d’utiliser du code qui n’est pas du Javascript et de le faire tourner dans ton navigateur. Ce code peut être par exemple du C, C++, Rust et plein d’autres. Il sera compilé et tournera dans ton navigateur à une vitesse quasi native sur ton CPU. Ce code est sous forme de fichier binaire que tu peux utiliser directement depuis Javascript comme un module.
Car oui, WebAssembly n’est pas là pour remplacer Javascript. Au contraire, ces deux technologies sont faites pour travailler ensemble. En utilisant l’API Javascript tu peux loader des modules WebAssembly dans ta page. Ce qui veut dire que tu peux profiter des performances de code compilé via WebAssembly avec la flexibilité de Javascript. C’est internet qui va être content.
Le nom WebAssembly est un peu trompeur. Le WebAssembly fonctionne en effet pour le Web mais il n’y est pas limité ! L’équipe qui a fait WebAssembly s’est bien fait chier à le faire de façon générique pour qu’il soit utilisé partout. On commence à en voir des exemples.
Ensuite, il y a une idée fausse qui revient tout le temps. WebAssembly n’est pas un langage de programmation. WebAssembly est un format intermédiaire, un bytecode, qui agit comme une cible de compilation pour d’autres langages. OK, c’est pas clair faisons des dessins.
Comment ça marche ?
T’as vu ça ? Encore une oeuvre d’art ce que je te propose comme schéma aujourd’hui. Tu me crois si je te dit que j’utilise Photoshop ?
Étape 1 : c’est toi et tes skills de développeurs. Tu produis du code source en C, C++ (y’en a d’autres). Ce code-là est censé régler un problème ou faire un process trop intensif pour Javascript dans le navigateur.
Étape 2 : tu vas utiliser Emscripten pour faire la traduction. Emscripten est une chaîne d’outil, construit avec LLVM, qui va compiler ton code source en WebAssembly. Tu peux l’installer et compiler ce que tu veux en quelques étapes rapide, on va regarder ça juste après. À la fin de cette étape, tu auras un fichier WASM.
Étape 3 : tu vas utiliser le fichier WASM dans ta page web. Si tu viens du futur, tu peux loader ce fichier comme n’importe quels modules ES6 dans ta page. À l’heure où j’écris ces lignes, l’utilisation est légèrement plus complexe, mais rien de fifou.
Allez, on met les mains dedans.
Fais voir le code
Tout d’abord, il nous faut un petit bout de code en C++ à compiler. Là où certains vont te proposer Diablo 1 entier comme exemple, moi je vais rester dans la simplicité avec une fonction qui additionne deux chiffres. On va pas prouver la vitesse de C++ avec ça, c’est pour l’exemple.
int add(int firstNumber, int secondNumber) { return firstNumber + secondNumber; }
Ensuite direction la distribution Linux de ton choix. On va commencer par télécharger et installer emscripten.
# on installe les dépendances python et git sudo apt-get install python2.7 git # on va chercher emscripten via un git clone git clone https://github.com/emscripten-core/emsdk.git # on s'installe dans le dossier cloné cd emsdk # on télécharge (c'est gros) et on installe le SDK ./emsdk install latest # on active le SDK ./emsdk activate latest # on ajoute les variables d’environnement et on met à jour le PATH pour le terminal actuel source ./emsdk_env.sh # on vérifie que l'installation s'est bien passée emcc --version # on compile notre fichier C en template WebAssembly emcc helloWebassembly.cpp -s WASM=1 -o helloWebassembly.html # on sert le HTML et on regarde le résultat emrun helloWebassembly.html
C’était la manière hackerman de faire le wasm. Y’a plus simple que ça. Tu peux aller sur ce site et mettre ton code C++ sur la gauche. Ensuite tu récupères le nom de la fonction exportée dans la partie WAT. Chez moi c’est « _Z3addii ». Tu n’as plus qu’à cliquer sur download et tu vas récupérer ton fichier wasm.
Dernière étape, on va le faire tourner dans une page web.
<html> <head> <title>WASM test</title> <link rel="stylesheet" href="/stylesheets/style.css" /> </head> <body> <script> const getRandomNumber = () => Math.floor(Math.random() * 10000); WebAssembly.instantiateStreaming( fetch("https://012q1.sse.codesandbox.io/wasm/add.wasm") ) .then(obj => obj.instance.exports._Z3addii) .then(add => { document.getElementById("addTarget").textContent = add( getRandomNumber(), getRandomNumber() ); }); </script> <h1>Résultat du C++</h1> <p id="addTarget"></p> </body> </html>
Et voici la page web qui permet d’utiliser le C++ compilé en WebAssembly ! Je passe sur tout le HTML et les trucs évidents pour aller directement à la ligne 11 avec la fonction InstantiateStreaming. Comme le raconte la documentation Mozilla, cette fonction permet de compiler et d’instancier notre module WebAssembly via un simple fetch.
Ensuite, je récupère la fonction add via le nom qu’on a récupéré auparavant et je l’utilise pour remplacer un bout de DOM. Et TADA ! Du C++ via du Javascript dans ton internet. C’est pas fou ça ? Tiens regarde, je t’ai même fait une codesandbox avec une démo fonctionnelle.
Tu vas me dire que c’est complexe juste pour faire ça, et t’as raison. Ils sont entrain de bosser pour remplacer le bout de Javascript d’instanciation par un simple import dans le futur. Donc patience ça va venir. On est trop dans le futur pour le moment.
Épilogue
Ça fait déjà cinq minutes qu’on discute donc je m’arrête là. Tu veux faire pareil avec du Rust ? Je te conseille cet excellent article. Tu veux tout savoir sur WebAssembly et tu as du temps devant toi ? Je te conseille cet excellent article. Pour la suite de l’histoire, j’attends avec impatience ce que va nous amener cette ouverture du web sur d’autres langages. Y’a beaucoup de potentiel et on n’est pas au bout de nos surprises.
Pour nuancer : https://twitter.com/aral/status/1206173737730674688
Python 2.7, c’est pas un truc obsolète ?
Bravo Mehdi ! Job accompli ! J’ai bien compris à quoi sert Web Assembly et j’ai déjà quelques idées d’utilisations.
Un grand merci à toi !
Super. C’est un bon article, simple et concis. J’aimerais avoir une idée d’un petit projet réalisable avec !😅
Super explication ! J’ai enfin compris les bases de WebAssembly en quelques minutes. Merci pour les exemples clairs et concis !