← Articles

jsg : un petit assistant pour les projets ruby.wasm

ruby.wasm fait tourner CRuby dans le navigateur, et le gem js sert de pont entre votre code Ruby et le monde JavaScript. Lancer un projet demande pourtant encore quelques étapes manuelles : une page HTML, le script du navigateur, un Gemfile, une commande de build et un serveur web local.

En 2024, j’ai regroupé ces étapes dans un petit gem appelé jsg. Son gemspec le résume en une ligne : « JSG helps setting up ruby.wasm projects and comes with a nicer syntax ». Il y a donc deux moitiés : un outil en ligne de commande qui met en place et construit un projet, et un fichier Ruby que vous chargez dans le navigateur.

Un avertissement d’abord : jsg est une expérience à un stade précoce. La version actuelle est la 0.1.2 de mai 2024, le README sur GitHub est encore le texte par défaut de Bundler, et il n’existe pas encore de véritable suite de tests. Cet article est ce qui se rapproche le plus d’une documentation.

Installation

jsg nécessite Ruby 3.0 ou plus récent et dépend du gem js (~> 2.6) et de erb :

gem install jsg

L’outil en ligne de commande

Le gem fournit un exécutable jsg avec trois commandes :

jsg new myapp   # create a project from the template, then build it
jsg build       # bundle install, then build assets/ruby-app.wasm
jsg server      # serve the current directory with WEBrick

jsg new myapp copie le modèle dans un nouveau dossier myapp. Vous obtenez :

Juste après la copie, il se place dans le dossier et lance le build. jsg build fait exactement deux choses : bundle install et rbwasm build -o assets/ruby-app.wasm. Le commentaire dans le src/main.rb du modèle explique l’idée : votre code va là et se retrouve dans le fichier .wasm après jsg build.

jsg server (ou jsg serve) démarre WEBrick sur le port 8080 et passe au port suivant si 8080 est déjà pris. Le dossier d’exemples utilise plutôt le one-liner intégré à Ruby, qui fonctionne tout aussi bien :

ruby -run -e httpd . -p 8080

Les deux reposent sur WEBrick, qui ne fait plus partie de la bibliothèque standard de Ruby depuis Ruby 3.0 ; il faudra donc peut-être d’abord un gem install webrick.

La « syntaxe plus agréable »

La seconde moitié est jsg.rb. Il définit un module JSG avec quelques raccourcis et ajoute une série de méthodes à JS::Object. Voici le Ruby qu’exécute la page d’exemple du dépôt :

require 'jsg'

$window = JSG.global
$d = $window.document

$d.getElementById("spinner").style.display = "none"

$d.createElement("h2").tap {|e|
    e.innerText = "Examples"
    $d.body.appendChild(e)
}

Au lieu de JS.global[:document], vous écrivez $window.document, et vous appelez les méthodes DOM comme en JavaScript. Voici ce que le code source ajoute :

L’index.html du modèle montre aussi une astuce pour le développement : il redéfinit require_relative pour charger les fichiers par HTTP via JS::RequireRemote. Le commentaire précise que ce n’est nécessaire que si vous voulez utiliser require_relative au lieu de jsg build.

État

jsg est petit et encore un peu brut. Si vous l’essayez et que quelque chose ne fonctionne pas, le code source est court : un fichier Ruby pour le côté navigateur et un script dans exe/jsg. Issues et pull requests sont les bienvenues sur GitHub. La licence est MIT.

ruby.wasm apparaît aussi dans un autre de mes projets : le portage de Hackety Hack derrière clogs dispose d’un build navigateur qui exécute CRuby compilé en WebAssembly.