What the server sends
When a server renders the page, Markless sends HTML plus a state record, a view record, and a small inline resumer, all inside one container div.
Last page, the compiler planned the state and view records for Counter.tsrx. When a server renders the page, those records travel inside the HTML.
HTML with notes taped inside
The payload is everything the server adds to your HTML so the browser can continue. The server runs the component body once. Then it writes two JSON notes: the state values, and which element does what. A small script waits beside them.
Think of a model house with the wiring diagram taped inside the door. That is an analogy. Nobody rebuilds the house to make the doorbell work.
Point at each part of the HTML.
What is inside the server HTML for Counter?
Point at any part of the HTML, or tab to it. The panel names what it is.
Point at a part of the HTML.
Counted from the view note above.
Only the button shows. Press it to find its HTML.
Real output of renderToString() for Counter.tsrx, built with the Markless Vite plugin. The two inline script bodies are cut to …, and line breaks are added. The counts are read from this JSON. This is one environment's format. In the browser, render() builds the DOM and writes none of these parts.
Notice that the button carries no event attribute. The click lives only in the view note.
The real response
I built Counter.tsrx with the Markless Vite plugin and called renderToString(). I cut the two inline scripts to …:
<link rel="modulepreload" href="/build/chunk--CpAagRl.js" crossorigin="anonymous" fetchpriority="high">
<script>(function captureEarlyEvents(eventNames) { … })(["click"]);</script>
<div data-async-container>
<button>Count 0</button>
<script type="markless/state">{"version":1,"cells":[{"graphNodeId":"state:count","name":"count","valueKind":"scalar","value":{"version":1,"root":0,"records":[]}}],"computed":[],"sharedDefinitions":[]}</script>
<script type="markless/view">{"version":1,"locators":[{"hostNodeId":"h0","strategy":"dom-order","index":1,"tagName":"button"}],"events":[{"hostNodeId":"h0","eventName":"click","symbolIds":["symbol:0"]}],"domUpdates":[{"hostNodeId":"h0","source":"count","graphNodeId":"state:count","path":[],"target":{"kind":"text","prefix":"Count "},"symbolId":"symbol:1"}],"behaviors":[],"elementHandles":[],"keyedRepeats":[],"branches":[],"asyncBoundaries":[]}</script>
<script data-async-resumer data-markless-resume-module="/build/chunk--CpAagRl.js">(function(e){ … })(…);</script>
</div>
- The
linklets the browser fetch the resume module early. The resumer imports it only after the first event. - The first script records events that fire before the page finishes loading. The resumer picks them up.
- In
"value":{"version":1,"root":0,"records":[]},rootholds the number0. Objects and arrays go intorecords.
Prerendered pages differ. They omit both notes, and the resume module rebuilds the records. Prerendering is a preview.
Next: What happens when someone clicks the button for the first time? Resuming →
