Chapter 5 · 14 July – 17 September
Raku in a browser tab
The interpreter is portable C++ with no dependencies, and that is exactly what compiles to WebAssembly. Twelve days after the first commit, Raku++ ran in a browser tab with no server behind it. It was the same interpreter, not a port. Two months later a second route to the browser followed: Raku compiled to JavaScript.
fib(29) compiled to JavaScript, against 297 ms interpretedRaku.js
- The first build: a build script, a thin C entry point, and a playground with the engine in a worker. It first went live as the course's playground.
- WebAssembly builds are attached to every release, and the first browser showcase applications arrive.
- raku.online replaces the course's playground as the place to run Raku in a browser.
- The playground moves to /play, and the site around it grows into the sections along the top of this page.
Three choices in the build were measured, not assumed:
- Classic exceptions. The interpreter uses C++ exceptions for
next,lastandreturn. With the newer WebAssembly exception model those catches failed and the loop trapped withRuntimeError: unreachable, so the build ships the older model. - A worker. The engine runs off the main thread, so the page stays responsive: output streams, a spinner turns, and Stop works.
- Built for size.
-Ozbeat-O2on both counts. It was smaller, and it recursed deeper: 206 levels against 174.
Recursion depth is the browser's real limit. A plain recursive sub reaches 58 levels in a Chrome worker and 115 on Chrome's main thread; in Safari, 32 and 419. When a worker's stack overflows, the run is retried on the main thread.
The tax for running in WebAssembly is 1.3× to 6.8× against the native binary, depending on the program. Even so, the WebAssembly engine's big-integer kernel (41.7 ms under Node) outran native Rakudo on the same kernel (258.9 ms) when it was measured.
Raku as JavaScript
On 3 September a proposal to retire Rakudo's own JavaScript backend cited Raku++ in the browser. The same week, Raku++ gained --target=js: a second code generator whose output is JavaScript source rather than C++. It trades completeness for speed, size and access to the host. What it cannot compile falls back to the WebAssembly engine. Anything that parses at run time, such as EVAL, stays WebAssembly-only for good.
- The first code: the six starting kernels agree, and the regression corpus reads 60 agreeing programs.
fib(29)takes 65 ms against 297 ms interpreted. - Interop with the host through
use JS, then regexes and grammars, source maps, and supplies. Three showcases: an eclipse, a Fourier drawing and orbits. The eclipse is 690 lines of Raku that become 425 KB of JavaScript. use jsbecomes a pragma, a directive to the compiler likestrict, rather than a module.- v4.0.0: bun is the default host, and
--fallback=wasmresolves the engine before requiring it.
Things that broke on the way
- On 29 August the playground's engine turned out to have been built by a compiler two releases old, because nothing checked which one had built it.
- Four documents said the browser engine had no files. The in-memory filesystem had been there all along.
- The copy-and-patch JIT (the compiler chapter) broke the WebAssembly build twice before it was fenced off.