Introduction à WebAssembly: Premiers pas avec WebAssembly

WebAssembly promet un tout nouveau type de Web: des performances accrues pour les utilisateurs et plus de flexibilité pour les développeurs. Au lieu de se limiter à utiliser JavaScript comme seul langage pour l'interaction Web côté client, un développeur peut choisir parmi un large éventail d'autres langages (C, TypeScript, Rust, Ruby, Python) et travailler dans celui qui lui convient le mieux. avec.

À l'origine, la seule façon de créer WebAssembly (ou WASM en abrégé) était de compiler du code C / C ++ en WebAssembly à l'aide de la chaîne d'outils Emscripten. Aujourd'hui, non seulement les développeurs ont plus d'options de langage, mais il est devenu plus facile de compiler ces autres langages directement dans WebAssembly, avec moins d'étapes intermédiaires.

Dans cet article, nous examinerons les étapes requises pour implémenter les composants WebAssembly dans une application Web. Étant donné que WebAssembly est un travail en cours, les étapes dépendent fortement de la langue que vous utilisez et la chaîne d'outils est susceptible de continuer à changer pendant un certain temps. Mais à l'heure actuelle, il est possible d'écrire et de déployer des applications WebAssembly utiles, bien que minimes, dans un certain nombre de langues.

Choisissez une langue prise en charge par WebAssembly

La première étape du déploiement d'une application WebAssembly consiste à choisir un langage qui peut compiler vers WebAssembly en tant que cible. Il y a de fortes chances qu'au moins un des principaux langages que vous utilisez en production puisse être converti en WebAssembly, ou dispose d'un compilateur qui peut émettre WebAssembly.

Voici les pionniers:

  • C. Evidemment. Le moyen typique de transformer le code C en WebAssembly est via Emscripten, car C-to-Emscripten-to-WebAssembly a été la première chaîne d'outils WebAssembly à venir. Mais d'autres outils émergent. Un compilateur entier, Cheerp, a été conçu spécifiquement pour générer des applications WebAssembly à partir de code C / C ++. Cheerp peut également cibler JavaScript, asm.js ou toute combinaison des éléments ci-dessus. Il est également possible d'utiliser la chaîne d'outils Clang pour créer des charges utiles WebAssembly, bien que le processus nécessite encore beaucoup de levage manuel. (Voici un exemple.)
  • Rouille. Le langage de programmation des systèmes de Mozilla, conçu pour être à la fois sûr et rapide, est l'un des principaux candidats à la prise en charge native de WebAssembly. Les extensions de la chaîne d'outils Rust vous permettent de compiler directement du code Rust vers WebAssembly. Vous devez utiliser la nightlychaîne d'outils de Rust pour effectuer la compilation WebAssembly, cette fonctionnalité doit donc être considérée comme expérimentale pour le moment.
  • TypeScript . Par défaut, TypeScript compile en JavaScript, ce qui signifie qu'il peut à son tour être compilé en WebAssembly. Le projet AssemblyScript réduit le nombre d'étapes impliquées, permettant à TypeScript strictement typé d'être compilé en WebAssembly.

Plusieurs autres langages commencent à cibler WebAssembly, mais ils n'en sont qu'à leurs débuts. Les langages suivants peuvent être utilisés pour créer des composants WebAssembly, mais uniquement de manière plus limitée que C, Rust et TypeScript:

  • D . Le langage D a récemment ajouté la prise en charge de la compilation et de la liaison directe avec WebAssembly.
  • Java . Le bytecode Java peut être compilé à l'avance dans WebAssembly via le projet TeaVM. Cela signifie que tout langage qui émet du bytecode Java peut être compilé en WebAssembly - par exemple, Kotlin, Scala ou Clojure. Cependant, de nombreuses API Java qui ne peuvent pas être implémentées efficacement dans WebAssembly sont restreintes, telles que les API de réflexion et de ressources, de sorte que TeaVM - et donc WebAssembly - n'est utile que pour un sous-ensemble d'applications JVM. 
  • Lua . Le langage de script Lua a une longue histoire d'utilisation en tant que langage intégré, tout comme JavaScript. Cependant, les seuls projets pour transformer Lua en WebAssembly impliquent l'utilisation d'un moteur d'exécution dans le navigateur: wasm_lua intègre un runtime Lua dans le navigateur, tandis que Luwa JIT-compile Lua en WebAssembly.
  • Kotlin / Native . Les fans du langage Kotlin, un spin-off de Java, attendaient avec impatience la sortie complète de Kotlin / Native, un back-end LLVM pour le compilateur Kotlin capable de produire des binaires autonomes. Kotlin / Native 0.4 a introduit la prise en charge de WebAssembly comme cible de compilation, mais uniquement comme preuve de concept.
  • .Net . Les langages .Net ne prennent pas encore en charge WebAssembly à part entière, mais certaines expériences ont commencé. Voir Blazor, qui peut être utilisé pour créer des applications Web d'une seule page dans .Net via C # et la syntaxe «Razor» de Microsoft.
  • Nim . Ce langage en devenir compile en C, donc en théorie, on pourrait compiler le C résultant en WebAssembly. Cependant, un back-end expérimental pour Nim appelé nwasm est en cours de développement.
  • Autres langages alimentés par LLVM . En théorie, tout langage qui exploite le framework de compilateur LLVM peut être compilé en WebAssembly, puisque LLVM prend en charge WebAssembly comme l'une des nombreuses cibles. Cependant, cela ne signifie pas nécessairement qu'un langage compilé par LLVM fonctionnera tel quel dans WebAssembly. Cela signifie simplement que LLVM facilite le ciblage de WebAssembly.

Tous les projets ci-dessus convertissent le programme d'origine ou le bytecode généré en WebAssembly. Mais pour les langages interprétés comme Ruby ou Python, il existe une autre approche: au lieu de convertir les applications elles-mêmes, on convertit le runtime du langage  en WebAssembly. Les programmes s'exécutent ensuite tels quels sur le runtime converti. Étant donné que de nombreux environnements d'exécution de langage (y compris Ruby et Python) sont écrits en C / C ++, le processus de conversion est fondamentalement le même que pour toute autre application C / C ++.

Bien sûr, cela signifie que le runtime converti doit être téléchargé dans le navigateur avant que des applications puissent être exécutées avec lui, ce qui ralentit les temps de chargement et d'analyse. Une version WebAssembly «pure» d'une application est plus légère. Ainsi, la conversion d'exécution est au mieux une mesure provisoire jusqu'à ce que davantage de langues prennent en charge WebAssembly comme cible d'exportation ou de compilation.

Intégrer WebAssembly avec JavaScript

La prochaine étape consiste à écrire du code dans le langage que vous avez choisi, en prêtant une certaine attention à la façon dont ce code interagira avec l'environnement WebAssembly, puis à le compiler dans un module WebAssembly (un binaire WASM), et enfin à intégrer ce module avec un existant Application JavaScript.

Les étapes exactes d'export du code vers WebAssembly varient énormément en fonction de la chaîne d'outils. Ils différeront également quelque peu de la façon dont les binaires natifs normaux sont construits pour cette langue. Par exemple, dans Rust, vous devrez suivre plusieurs étapes:

  1. Configurez la nightly construction pour Rust, avec la wasm32-unknown-unknownchaîne d'outils.
  2. Écrivez votre code Rust avec les fonctions externes déclarées comme #[no-mangle].
  3. Créez le code à l'aide de la chaîne d'outils ci-dessus.

(Pour un aperçu détaillé des étapes ci-dessus, consultez le livre Rust and WebAssembly sur GitHub.)

Il convient de noter que quel que soit le langage que vous utilisez, vous devez avoir au moins un niveau minimal de compétence en JavaScript pour intégrer le code à un frontal HTML. Si les extraits de code JavaScript dans la page de cet exemple de The Rust and WebAssembly Book vous semblent grecs, prévoyez du temps pour apprendre au moins suffisamment de JavaScript pour comprendre ce qui se passe là-bas.

L'intégration de WebAssembly et JavaScript se fait en utilisant l' WebAssemblyobjet en JavaScript pour créer un pont vers votre code WebAssembly. Mozilla a une documentation sur la façon de procéder. Voici un exemple WebAssembly distinct pour Rust, et voici un exemple WebAssembly pour Node.js.

À l'heure actuelle, l'intégration entre le backend WebAssembly et le frontal JavaScript / HTML est toujours la partie la plus lourde et la plus manuelle de tout le processus. Par exemple, avec Rust, les ponts vers JavaScript doivent encore être créés manuellement, via des pointeurs de données brutes.

Cependant, de plus en plus d'éléments de la chaîne d'outils commencent à résoudre ce problème. Le framework Cheerp permet aux programmeurs C ++ de parler aux API du navigateur via un espace de noms dédié. Et Rust propose wasm-bindgen, qui sert de pont bidirectionnel entre JavaScript et Rust, et entre JavaScript et WebAssembly.

En outre, une proposition de haut niveau sur la manière de gérer les liaisons avec l'hôte est à l'étude. Une fois finalisé, il fournira un moyen standard pour les langages qui se compilent vers WebAssembly d'interagir avec les hôtes. La stratégie à long terme avec cette proposition englobe également les liaisons avec des hôtes qui ne sont pas des navigateurs, mais les liaisons de navigateur sont le cas d'utilisation immédiat à court terme.

Débogage et profilage des applications WebAssembly

La prise en charge du débogage et du profilage est un domaine dans lequel les outils WebAssembly en sont encore à leurs débuts. 

Jusqu'à l'arrivée des cartes source JavaScript, les langages compilés en JavaScript étaient souvent difficiles à déboguer car le code original et compilé ne pouvait pas être corrélé facilement. WebAssembly a certains des mêmes problèmes: si vous écrivez du code en C et le compilez dans WASM, il est difficile de dessiner des corrélations entre la source et le code compilé.

Les cartes source JavaScript indiquent quelles lignes du code source correspondent à quelles régions du code compilé. Certains outils WebAssembly, comme Emscripten, peuvent également émettre des cartes source JavaScript pour le code compilé. L'un des plans à long terme de WebAssembly est un système de carte source qui va au-delà de ce qui est disponible en JavaScript, mais ce n'est encore qu'au stade de la proposition.

À l'heure actuelle, le moyen le plus direct de déboguer le code WASM à l'état sauvage consiste à utiliser la console de débogage du navigateur Web. Cet article sur WebAssemblyCode montre comment générer du code WASM avec une carte source, le rendre disponible pour les outils de débogage du navigateur et parcourir le code. Notez que les étapes décrites dépendent de l'utilisation de l' emccoutil pour émettre le WASM. Vous devrez peut-être modifier les étapes en fonction de votre chaîne d'outils particulière.