· via dev.to (home feed)
Fitz adds isomorphic hydration: server paints the HTML, a WASM runtime adopts the DOM
Fitz's new opt-in hydration has the server render a component to HTML while a compiled WASM client adopts those exact DOM nodes, restoring state without reconciliation or a shipped framework runtime.

Adoption instead of reconciliation
The eighth installment of Martin Palopoli's FitzLiveViews series on dev.to details a new hydration path in the Fitz framework: a single .fitzv component can now render to HTML on the server for a fast first paint, and then hand that exact DOM over to a compiled WebAssembly client. Instead of rebuilding the page or reconciling a virtual DOM against the server's output, the WASM runtime adopts the existing nodes — walking them, restoring serialized state, and attaching event listeners in place.
The feature is opt-in. Adding a hydrate marker to a component declaration makes its two compiled outputs — server HTML and a standalone WASM app — cooperate. Palopoli notes the marker is deliberately optional so that components rendered for Fitz's LiveViews WebSocket takeover, whose DOM diffing forbids a script tag inside the root, stay byte-identical to before.
What the server sends
According to the post, the SSR emitter performs a genuine render-to-string of the component rather than relying on a hand-authored shell. Alongside the rendered HTML it embeds a JSON script payload keyed to the component, carrying its state so the client boots from the server's values rather than template defaults.
The server also leaves adoption markers the client can walk: paired HTML comments around text interpolations and around {#if} and {#for} regions, a wrapper div around composed child components, and slot content inlined into the parent's scope.
What the client does at boot
Hydratable components run hydrate() rather than mount(). The runtime sees the mount root already has content, restores the serialized state — primitives plus composites such as lists, string-keyed maps, nullables and imported nominal types that round-trip through JSON — then walks the existing DOM depth-first with a cursor, mapping each element, text and comment node onto the same internal handles a fresh build would have created. No create_element, no wiping the root. Event listeners are then wired onto the adopted nodes.
From that point on, state changes patch in place using keep-node reconciliation, which Palopoli says keeps a focused input's caret intact because the page is never rebuilt.
The flow was verified end-to-end in real Chrome via Puppeteer, including a test that sets a JavaScript property on a server-painted node before initialization: the property survives hydration, demonstrating that the node was adopted rather than recreated. Four runnable examples cover the base case, mixed static and interpolated text, conditional and list regions, and composition with child components and slots.
Positioning against React, Astro and LiveView
The post is candid that hydration is largely a solved problem in the JavaScript world; its argument is about cost. React and Next.js ship the framework runtime to the client and run a reconciliation pass against the server HTML, and mismatches between the two generate an entire category of warnings. Astro's islands and partial hydration reduce what ships, but each island still embeds a JavaScript framework runtime. Phoenix LiveView and Hotwire keep the client as a thin JS layer patching the DOM on the server's behalf, whereas Fitz's client is a full compiled app with its own state that simply starts from the server's DOM instead of a blank mount.
The claimed differentiator is the combination: one source file for both ends, node-for-node adoption, opt-in per component, keep-node patching afterward, and no framework runtime over the wire.
Known limitations of the MVP
Palopoli lists the honest edges. Hydration is opt-in per component, with universal auto-hydration flagged as future work. Composite state restores correctly, but types that cannot survive a JSON round-trip — a map with a non-string key, tuples, functions — reset to their defaults on restore. Named slots in the SSR emitter and dynamic composition inside conditional or list regions are deferred to later slices; the default slot and static composition work today. The series' next installment will cover a companion UI library of roughly 40 importable components extracted from a real admin application.
Why it matters
For web developers, the interesting idea here is cutting the knot between server-rendered HTML and client interactivity. One source produces both ends, and the handover preserves DOM identity completely: no re-render flash, no hydration mismatch warnings, and no framework runtime shipped to the browser. Fitz remains a young project whose author frames this as an MVP rather than a production-ready rival to Next.js, but adoption-based hydration driven by a WASM runtime is a concrete data point in the wider conversation about moving frontend logic out of JavaScript entirely.
- #fitz
- #webassembly
- #hydration
- #server-side-rendering
- #frontend