← Blog

jsg: ein kleiner Helfer für ruby.wasm-Projekte

Mit ruby.wasm läuft CRuby im Browser, und das js-Gem ist die Brücke zwischen Ihrem Ruby-Code und der JavaScript-Welt. Bis ein Projekt steht, sind trotzdem einige Handgriffe nötig: eine HTML-Seite, das Browser-Script, ein Gemfile, ein Build-Befehl und ein lokaler Webserver.

2024 habe ich diese Schritte in ein kleines Gem namens jsg gepackt. Die Gemspec fasst es in einem Satz zusammen: jsg hilft beim Aufsetzen von ruby.wasm-Projekten und bringt eine angenehmere Syntax mit. Es besteht also aus zwei Teilen: einem Kommandozeilen-Tool, das ein Projekt anlegt und baut, und einer Ruby-Datei, die Sie im Browser laden.

Vorweg ein ehrlicher Hinweis: jsg ist ein frühes Experiment. Die aktuelle Version ist 0.1.2 vom Mai 2024, das README auf GitHub ist noch der Platzhalter von Bundler, und eine richtige Testsuite gibt es noch nicht. Dieser Beitrag ist das, was einer Dokumentation am nächsten kommt.

Installation

jsg benötigt Ruby 3.0 oder neuer und hängt vom js-Gem (~> 2.6) und von erb ab:

gem install jsg

Das Kommandozeilen-Tool

Das Gem bringt ein jsg-Programm mit drei Befehlen mit:

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 kopiert die Vorlage in einen neuen Ordner myapp. Darin finden Sie:

Direkt nach dem Kopieren wechselt der Befehl in den Ordner und startet den Build. jsg build macht genau zwei Dinge: bundle install und rbwasm build -o assets/ruby-app.wasm. Der Kommentar in src/main.rb erklärt die Idee: Ihr Code gehört dorthin und landet nach jsg build in der .wasm-Datei.

jsg server (oder jsg serve) startet WEBrick auf Port 8080 und weicht auf den nächsten Port aus, falls 8080 schon belegt ist. Der Beispielordner verwendet stattdessen den eingebauten Einzeiler von Ruby, der genauso gut funktioniert:

ruby -run -e httpd . -p 8080

Beide brauchen WEBrick, das seit Ruby 3.0 nicht mehr zur Standardbibliothek gehört. Unter Umständen ist also zuerst ein gem install webrick nötig.

Die «angenehmere Syntax»

Der zweite Teil ist jsg.rb. Die Datei definiert ein Modul JSG mit einigen Abkürzungen und ergänzt JS::Object um eine Reihe von Methoden. Das ist der Ruby-Code, den die Beispielseite im Repository ausführt:

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)
}

Statt JS.global[:document] schreiben Sie $window.document und rufen DOM-Methoden so auf, wie Sie es aus JavaScript kennen. Das ergänzt der Quellcode:

Die index.html der Vorlage zeigt ausserdem einen Kniff für die Entwicklung: Sie definiert require_relative neu, sodass Dateien über HTTP mit JS::RequireRemote geladen werden. Laut Kommentar ist das nur nötig, wenn Sie require_relative statt jsg build verwenden möchten.

Stand

jsg ist klein und hat noch Ecken und Kanten. Wenn Sie es ausprobieren und etwas nicht funktioniert: Der Quellcode ist kurz, eine Ruby-Datei für den Browser und ein Script in exe/jsg. Issues und Pull Requests sind auf GitHub willkommen. Die Lizenz ist MIT.

ruby.wasm taucht auch in einem anderen Projekt von mir auf: Die Hackety-Hack-Portierung hinter clogs hat einen Browser-Build, in dem CRuby als WebAssembly läuft.