The SSR Model FULL
What server-side rendering means in WildflowerJS, and why it looks different from the model you may be expecting.
Two different arrangements
In Next, Nuxt, SvelteKit, and SolidStart, the framework runs on the server. Your component code executes twice, once in a Node process to produce an HTML string and again in the browser to hydrate that string back into a live component tree. The server render and the client render must agree, and when they disagree you get a hydration mismatch.
WildflowerJS inverts where the HTML comes from. Your backend produces it, however it already does, and the framework only ever runs in the browser. It reads state out of the markup it finds, marks that markup as already correct, and attaches reactivity to it.
The practical consequence is that there is no second render to disagree with the first. Server content is the only render of that content that ever happens, so the class of bug where server and client produce different output does not arise.
There is no renderToString
WildflowerJS ships no server-side rendering API. There is no renderToString, no renderToStream, and no server entry point, because no part of the framework is designed to run outside a browser.
The equivalent step in WildflowerJS is whatever your backend already uses to render a page, a Blade template, an ERB view, a Django template, or a Go html/template.
data-ssr="true" to a component root and the framework treats the content inside as authoritative. Everything else is the same markup you would write by hand.
<!-- Rendered by your backend, whatever language it is -->
<div data-component="user-profile" data-ssr="true">
<h2 data-bind="name">Ada Lovelace</h2>
<span data-bind="visits" data-type="number">42</span>
<button data-action="refresh">Refresh</button>
</div>
The browser parses name as the string "Ada Lovelace" and visits as the number 42, wires the button to your refresh method, and leaves the existing DOM nodes in place. See Server-Side Rendering for the full set of data types and data-seed for state that never appears as visible text.
Any backend, no Node
Because the framework never executes on the server, the server has no JavaScript requirement at all, and is agnostic about the backend itself. Anything qualifies, as long as what it sends is HTML the framework can adopt. There is no Node process in the deployment, no build step that has to run before the server can answer a request, and no version coupling between your backend runtime and your frontend framework.
| Your backend | What it does | What WildflowerJS needs from it |
|---|---|---|
| PHP, Laravel, Symfony | Renders a Blade or Twig template | HTML containing data-component and data-ssr="true", with values as text and data-type where the value is not a string |
| Ruby on Rails | Renders an ERB view | |
| Python, Django, Flask | Renders a Django or Jinja template | |
| Go | Executes html/template |
|
| .NET | Renders a Razor page |
Advanced SSR has worked examples for Node and Express, PHP, and Django.
"Where is your Next.js?"
The question assumes the framework needs a server-side companion to be complete. That companion exists to run framework code on the server, handle the routing that depends on it, and manage the build that produces both halves. WildflowerJS has no server-side half to run, so there is nothing for such a layer to do.
Your existing backend already fills that role. It has routing, a template layer, sessions, authentication, and a database. The handoff between it and the browser starts with data-ssr="true", and for standing queries that continue past the first render, SSR with Data Queries describes the contract.
Streaming
Chunked responses work. A component that arrives in a later chunk is adopted when it arrives, with the same state parsing and type coercion as one present in the first chunk. The mechanism is a MutationObserver watching the document tree with subtree: true, so the browser's parser appending a node is itself the signal.
<!doctype html>
<html>
<head>
<script src="/js/wildflower.full.min.js"></script>
</head>
<body>
<div data-component="header" data-ssr="true">...</div>
<!-- flush -->
<div data-component="results" data-ssr="true">...</div>
<!-- flush -->
</body>
</html>
A component flushed 400 ms into a response is interactive while the response is still open and the document is still parsing. It does not wait for the response to close.
Definition order across chunks is forgiving in both directions. A component element that arrives before the <script> defining it is picked up when the definition registers. A component that subscribes to a store registered by a later chunk waits for that store to arrive before its init() runs, up to subscribeTimeout. Once the document has finished loading, a subscribed store that never appeared is reported as missing rather than waited for, so a mistyped store name still fails fast.
What this does not give you
Things to be aware of when working with WildflowerJS's SSR:
- Streaming has no orchestration layer. There are no flush boundaries you declare in component code and no selective hydration priority. Deciding what to flush and when is your server's job, using whatever its language offers.
- No server-rendered output from component definitions. A component defined in JavaScript cannot produce its own initial HTML. Anything that must appear in the first response has to be rendered by your backend template, which means the markup exists in two places when a component can render both server-side and client-side content.
- No JavaScript-based static site generation. There is no build command that walks routes and emits HTML files. Static generation, where you want it, comes from your backend or a separate static site tool.
- SEO depends entirely on your backend. The framework improves nothing about what a crawler sees, because it contributes nothing to the initial response. What your server sends is exactly what gets indexed.