Targets · JavaScript · Entry point
Entry point
Every rendered Program has a single generated entry point: a main() function that builds the native drivers from the driver spec, hands the run body to the reactive system, and starts the cycle. It is where a page of otherwise static JavaScript becomes a running, reactive program.
Contents
How a Program becomes JavaScript, in parts. Start with the introduction, then follow each part into the rendered output and the runtime it links against.
- Introduction — what the JavaScript target is, and how to read the rest of this section.
- Capabilities — which high-level features are possible, built in or through a library.
- Coding standards — the Frenzi coding standards the generated code follows, global and JavaScript-specific.
- Example — a full program using every keyword, and the JavaScript it renders to.
- Naming considerations — how Program's dotted names are carried into JavaScript.
- Entry point — the generated
main()that wires up the drivers and starts the reactive cycle. - Drivers — the native drivers that provide capabilities like the user interface and animation, draining each cycle's emissions.
- Runtime — the Reactive and Context machinery the rendered code links against.
- Native modules — the hand-written, per-platform JavaScript behind
NATIVEfunctions. - Keywords — how each of Program's keywords renders to JavaScript.
- Project setup — the files and commands to build and run the rendered program.
- Reserved words — the words JavaScript keeps for itself, and how a Program name that collides with one is escaped.
One call to start
A whole program starts with a single call. It takes the root component —
the run body, written as a callback — and the
drivers the embed should use, and returns a
cancel function that tears the program down again.
const cancel = Program.Application(
() => Counter(), // the root component — the program itself
[
Ui.Dom.Driver('app'), // render the interface into <div id="app">
]
);
That one call builds the drivers, creates the reactive program from the root component, runs the first cycle, and reconciles the result into the page. Everything after is the runtime reacting to change.
The cycle
That first call does not start a loop that spins. The runtime is demand-driven: it runs one cycle, then waits. A cycle is a single Reactive.Run — write-backs first, then the forward body, which emits the interface and effects into the drivers' channels. Then nothing happens until a driver has news.
When something outside changes — a click, a network reply, an animation frame — the driver
calls the addUpdates it was handed at startup. That schedules exactly one more cycle (on a
microtask, so a burst of updates coalesces into a single render), and Reactive.Run
receives those updates as it runs again. A program at rest costs nothing; continuous motion, like
animation, comes only from a driver that re-schedules itself every frame.
The friendly Program.Application(root, [drivers]) is a thin wrapper over the reserved
runtime entry Program._Runtime.Run(root, …drivers) — the _
marking it as glue the program can never name, the same convention that walls off a record's generated
helpers. It builds the reactive program from the root, initialises each driver with
addUpdates, runs the first cycle, and returns the cancel that stops it.
Attaching to the page
The interface is attached to one root element in the DOM. The DOM user-interface
driver takes that element — by id or as an element — and owns everything
inside it, patching it in place on each cycle rather than rebuilding it.
<div id="app"></div>
<script src="program-runtime.js"></script>
<script>
Program.Application(() => Counter(), [ Ui.Dom.Driver('app') ]);
</script>
Because the root is just an element, one page can host many independent programs at once,
each mounted into its own node. That is exactly how a live example is embedded in these pages: a
small program in an isolated <div>.
The run body is the root component
The callback passed first is the program. Its calls emit the interface, its state lives across cycles, and its nesting becomes nested closures in the rendered code — see the example. There is no separate template: the same reactive body that computes values also lays out the page.
Stopping
Program.Application returns a cancel function. Calling it stops the
cycle, tears down the drivers, and releases the root element — the clean end of a program's
life. Wire it to beforeunload for a whole-page app, or call it by hand for an embed
that comes and goes.
const cancel = Program.Application(() => Counter(), [ Ui.Dom.Driver('app') ]);
window.addEventListener('beforeunload', cancel);
// … later, to remove an embedded program:
cancel();