Skip to content
These are temporary community docs. The official docs are in progress.Help improve them
Markless
Esc
↑↓navigate↵open⌘Jpreview
On this page

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.

The response, from a serverone environment's format
What this part is

Point at a part of the HTML.

Locators1
Click events1
Text updates1

Counted from the view note above.

What the visitor sees
CounterHTML from a server

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 link lets 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":[]}, root holds the number 0. Objects and arrays go into records.

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 →

Was this page helpful?