Webraku
One Raku program, on the server and in the browser. Raku++ runs each page
on the server to answer the request with finished HTML, and
rakupp --target=js compiles the same file into the script the
browser runs, which picks the page up where the server left it.
Open the live demos Webraku on GitHub
use Webraku;
sub rendered-at(--> Str) is server { DateTime.now.hh-mm-ss }
page '/', :title('Counter'), {
my $n = 0;
main {
h1 'Camelia counts';
my $out = p 'clicked 0 times';
my $up = button 'Click me';
p "rendered on the server at {rendered-at()}";
react {
whenever $up.clicks { $out.text = "clicked {++$n} times" }
}
}
}
serve;
The clicks are counted in the browser, with no request after the page
loads. rendered-at is marked is server: its body
stays on the server, and the browser calls it over HTTP without anyone
writing a request, a route or a line of JSON. Its answer was written into
the page when the server rendered it, so the browser's first render does
not ask again, and the page is complete with JavaScript switched off.
The demos #
Each demo is one Raku program with a module or two beside it, and each draws the line between the two halves in a different place, for a different reason. The front page of the demo site shows, for every demo, which subs and modules stay on the server — read from its source by Webraku's own bundler.
Sudoku
A secret on the server. The rules are compiled into the page, so a repeated digit turns red on the keystroke. The solver is used only by server subs, so it is not in the browser’s script, and the solution is never sent: hints and checks are questions the server answers.
Unicode explorer
Data on the server. All 172,808 character names, from Raku++’s uniname, are searched on the server, with uniprop for the properties. UTF-8 bytes, UTF-16 units and the four ways to count a string are arithmetic, done in your browser as you type.
Pixels
State on the server, shared. One picture for everyone who has the page open. Painting is local and instant; once a second one server call sends your strokes and brings back everyone else’s.
Wavelet shrinkage
A library on both sides. Math::Wavelet is compiled into the page, so the discrete transform redraws on every slider step with no request; the continuous transform is computed on the server and sent as a picture.
Two small ones show the extremes: a sieve whose code never reaches the browser, only its answer, and a counter that needs nothing from the server once the page has loaded.
How one file becomes two programs #
| Pages | a page block builds the HTML with a sub per tag: div :class<card>, { h2 $title; p $text }. On the server it renders; in the browser the same block adopts the nodes the server sent. |
| State | plain Raku variables. A changed element is written into the page after the event that changed it; there is no virtual DOM. |
| Events | Supplies: whenever $button.clicks { … } in a react block, which in the browser is the page for as long as it is open. |
| Server code | sub load() is server { … }. Its body, and any module beside the program that only server code uses, stays out of the browser’s script. |
| Modules | a module the browser’s code calls is compiled into the script by rakupp --target=js, installed ones included. |
--target=js exists in no other Raku, so Webraku needs Raku++;
there are no other dependencies — no npm, no bundler, no JavaScript to
write. The HTTP server is Webraku’s own, in Raku. Webraku is version
0.0.1 and a work in progress.
Run it yourself #
$ rakupp install Webraku
$ webraku run hello.raku --port=8080
With a checkout of the repository, rakupp demo/run.raku --proxy=8080
serves every demo on one port, the way the demo site runs them, and
demo/README.md
says how to put them behind a proxy on a server of your own.
Next #
- The README — writing a page, the command, the modules, what is left out.
- Raku on a web page — the other way round: the whole interpreter in the browser, as WebAssembly, with no server at all.
- The showcase — servers and tools written in Raku and run by Raku++.