Ruby2JS Self-Hosting Update
Four commands and you have a Ruby-to-JavaScript converter running in Node.js:
wget https://www.ruby2js.com/demo/selfhost/ruby2js.mjs
chmod +x ruby2js.mjs
npm install @ruby/prism
./ruby2js.mjs -e 'puts "hello"'
That's it. No Ruby installation required.
Before running downloaded scripts, review them. The ruby2js.mjs file is generated JavaScript -- comments may be slightly relocated, but otherwise the code is readable, idiomatic, and nearly hand-coded. You can also browse the Ruby source that produced it.
What Changed Since November
In my previous post, I had a proof of concept: the core converter running in the browser at ~250KB. Since then, the self-hosting work has matured significantly.
All Converters Now Self-Hosted
The original post mentioned that basic literals, variables, and control flow worked. Now everything is transpiled:
- All 60+ converter handlers (classes, methods, blocks, regexps, etc.)
- The PrismWalker (translates Prism AST to Parser-compatible format)
- The Serializer (output formatting, indentation, comments)
- The Namespace tracker (class/module scope management)
- The Node class (AST representation)
The unified ruby2js.mjs bundle is about 200KB uncompressed and unminified (excluding Prism WASM). It works in Node.js CLI, browser imports, and CI tests -- same code everywhere.
245 Tests Passing
The transliteration test suite has been transpiled from Ruby to JavaScript. The same tests that validate the Ruby converter now validate the JavaScript version:
Ready specs:
transliteration_spec: 245 passed, 2 skipped
The two skipped tests involve Proc#source_location -- a Ruby introspection feature that doesn't translate to JavaScript. Everything else passes.
New Documentation
The Ruby2JS User's Guide is new, with live demos on every page:
- Dual-Target Ruby Development -- Write Ruby that runs both natively and as transpiled JavaScript
- JavaScript-Only Development -- Use Ruby syntax to write browser/Node.js code
- Pragmas in Practice -- Line-level control over transpilation via comments
- Anti-Patterns -- Ruby patterns that don't translate well
- ERB Filter -- Convert ERB templates to JavaScript functions for offline-first Rails apps
New Filters
Polyfill Filter -- Adds JavaScript prototype polyfills for Ruby methods that don't have direct equivalents. Instead of transforming .first to [0], it preserves the Ruby method name and adds a polyfill definition:
Object.defineProperty(Array.prototype, "first", {
get() { return this[0] },
configurable: true
});
Pragma Filter -- Extracted from the selfhost work into a general-purpose filter. Pragmas are comments that control transpilation:
x ||= default # Standard: may become ??= or ||= depending on context
y ||= default # Pragma: ?? # Force nullish coalescing
z ||= default # Pragma: logical # Force logical OR
Since pragmas are comments, they have no effect when code runs in Ruby -- making them perfect for dual-target development.
The Architecture
Ruby Source Code
|
v
@ruby/prism (WebAssembly, ~2.7MB)
|
v
Prism AST (JavaScript objects)
|
v
PrismWalker (transpiled from Ruby)
|
v
Parser-compatible AST
|
v
Converter + Handlers (transpiled from Ruby)
|
v
Serializer (transpiled from Ruby)
|
v
JavaScript Output
The key take-away: a "dual-target" approach that lets you maintain a single codebase that works in both environments is viable. This is the foundation for offline-first scoring in my showcase dance competition app -- sharing validation and business logic between Rails and the browser.
What's Not Done Yet
Filters aren't transpiled yet. The self-hosted version does basic transliteration -- Ruby syntax to JavaScript syntax. The filters that transform Ruby idioms to JavaScript idioms (functions, camelCase, esm, etc.) still require the Ruby version. But this is just a matter of time. I hope to be complete around the time that Ruby 4.0 is released (in about two weeks).
Try It
CLI (Node.js):
wget https://www.ruby2js.com/demo/selfhost/ruby2js.mjs
chmod +x ruby2js.mjs
npm install @ruby/prism
echo 'class Foo; def bar; 42; end; end' | ./ruby2js.mjs
Browser:
<script type="module">
import { convert } from 'https://www.ruby2js.com/demo/selfhost/ruby2js.mjs';
console.log(convert('puts "hello"'));
</script>
Or visit the self-hosted demo directly.
What This Enables
Self-hosting isn't just a technical curiosity. It proves that Ruby2JS can handle substantial, real-world Ruby code -- its own implementation. Patterns discovered during self-hosting have been extracted into general-purpose filters that benefit all users.
More practically, it means that "dual target" and offline-first functionality in Rails applications is achievable -- run the same Ruby code on the server and in the browser, with no runtime overhead.
Ruby2JS is open source: github.com/ruby2js/ruby2js