Jetstream islands v0.6
Server-reactive islands. State lives on the server; interactions go over a WebSocket and the server pushes an HTML patch — with zero component JavaScript on the client.
A regular island ships its component JS and runs in the browser. A Jetstream island ships none: the server holds its state per connection, re-renders on events, and sends a DOM patch that a ~2 KB runtime morphs in. It's Nowaki's answer to "content-driven but dynamic" UIs — live counters, dashboards, presence — without shipping a client framework.
Write one
Give an island an export const live with initial state andon handlers. Buttons reference handlers with data-live — noonClick, no client component.
// islands/LiveCounter.tsx
export const live = {
state: () => ({ count: 0 }),
on: {
inc: (s) => ({ ...s, count: s.count + 1 }),
dec: (s) => ({ ...s, count: s.count - 1 }),
reset: () => ({ count: 0 }),
},
};
export default function LiveCounter({ state }) {
return (
<div>
<button data-live="dec">-</button>
<strong>live: {state.count}</strong>
<button data-live="inc">+</button>
</div>
);
}How it works
- The build emits no client chunk for live islands; it SSRs them inside a
<nowaki-live>wrapper with the initial state. - The Rust front holds a
/__nowaki/liveWebSocket and keeps each island's state per connection. - A
data-liveevent is bridged to the Node renderer (a purestate → htmlfunction); the new HTML is pushed as a patch and morphed into the DOM. - Client and optimistic islands coexist on the same page.
Presence & scaling v0.9
- Presence — the server broadcasts the live connection count; clients receive
{ type: "presence", count }and it's mirrored into[data-nowaki-presence]elements (and anowaki:presenceevent). - Heartbeat — connections ping periodically and idle ones are dropped, so zombie connections don't leak state.
- Connection cap — a global limit (
NOWAKI_LIVE_MAX); over it, the client keeps the initial SSR view (graceful degradation).
Static and edge deploys serve the initial SSR and degrade gracefully without a WebSocket; the connected, reactive mode runs under
nowaki start (the Rust front holds the socket). Validate inputs in your on handlers as you would any server handler.