Server-Side Rendering (SSR) FULL
Seamlessly integrate server-rendered HTML with WildflowerJS components for optimal performance and SEO.
SSR Overview
WildflowerJS SSR enables you to:
- Preserve server-rendered content - No flashing or re-rendering
- Parse state from DOM - Components automatically extract their state from server HTML
- Maintain interactivity - Actions, events, and dynamic updates work normally
- Optimize performance - Skip unnecessary initial renders and binding updates
SSR Philosophy
"Server content is perfect - don't recreate it, just protect and enhance it"
WildflowerJS SSR follows a protection-first approach where server-rendered content is preserved and enhanced rather than replaced.
Basic Setup
Enable SSR by adding the data-ssr="true" attribute to your components:
Server-Rendered HTML:
<div data-component="user-profile" data-ssr="true">
<h2 data-bind="name">John Doe</h2>
<p data-bind="email">john@example.com</p>
<p data-bind="role">Administrator</p>
<button data-action="editProfile">Edit Profile</button>
</div>
name: "John Doe", email: "john@example.com", and role: "Administrator" from the server-rendered content.
State Hydration
WildflowerJS automatically parses server-rendered content into component state:
Data Type Support
| Data Type | Attribute | Example HTML | Parsed Value |
|---|---|---|---|
| String | none | <span data-bind="name">John</span> |
"John" |
| Number | data-type="number" |
<span data-bind="age" data-type="number">25</span> |
25 |
| Boolean | data-type="boolean" |
<span data-bind="active" data-type="boolean">true</span> |
true |
| JSON | data-type="json" |
<span data-bind="config" data-type="json">{"theme":"dark"}</span> |
{theme: "dark"} |
| HTML | data-type="html" |
<div data-bind="content" data-type="html"><b>Bold</b></div> |
"<b>Bold</b>" |
Server-Rendered HTML with Data Types:
<div data-component="data-showcase" data-ssr="true">
<div data-bind="username">johndoe</div>
<div data-bind="score" data-type="number">1250</div>
<div data-bind="verified" data-type="boolean">true</div>
<div data-bind="metadata" data-type="json">{"theme":"dark","lang":"en"}</div>
<button data-action="showState">Show Current State</button>
</div>
List SSR
SSR lists are particularly powerful - they preserve server-rendered content while enabling full dynamic functionality:
Server-Rendered List HTML:
<div data-component="user-list" data-ssr="true">
<h3>Users (<span data-bind="users.length">3</span>)</h3>
<div data-list="users">
<template>...</template>
<!-- Server-rendered list items -->
<div class="user-card">Alice Johnson - alice@example.com</div>
<div class="user-card">Bob Smith - bob@example.com</div>
<div class="user-card">Carol Davis - carol@example.com</div>
</div>
<button data-action="addUser">Add Random User</button>
</div>
Hidden Fields: data-seed
State hydration parses what the page displays. Data your components need that never appears as text, record ids, API paths, permission flags, cannot be recovered from the DOM. The data-seed attribute carries those fields as a small JSON object, rendered by the server on the element the data belongs to:
<!-- On the component root: unrendered state fields -->
<div data-component="user-profile" data-ssr="true" data-seed='{"userId":42}'>
<h2 data-bind="name">Ada Lovelace</h2>
</div>
<!-- On list item roots: unrendered item fields, most often the identity -->
<div data-list="users">
<template>...</template>
<div class="user-card" data-seed='{"id":11}'><span data-bind="name">Alice Johnson</span></div>
<div class="user-card" data-seed='{"id":12}'><span data-bind="name">Bob Smith</span></div>
</div>
Seed fields merge into the parsed state and win any overlap with display text, since the attribute is the machine value and the text is the formatted one. A count rendered as "250+" can carry data-seed='{"count":250}' and hydrate as a number. Each datum still exists once in the HTML: visible fields as text, hidden fields on the element they describe.
Mixed Components
You can mix SSR and regular components on the same page:
Mixed Component Types:
<!-- SSR Component - content preserved from server -->
<div data-component="server-stats" data-ssr="true">
<h3>Server Statistics</h3>
<p>Uptime: <span data-bind="uptime">24 days, 15 hours</span></p>
<p>Memory: <span data-bind="memory">2.4 GB</span></p>
</div>
<!-- Regular Component - dynamically rendered -->
<div data-component="client-stats">
<h3>Client Statistics</h3>
<p>Session Time: <span data-bind="sessionTime"></span></p>
<button data-action="incrementClicks">Click Me!</button>
</div>
Best Practices
✅ Do's
- Use for above-the-fold content - Critical content that needs immediate visibility
- Preserve semantic HTML - Server content should be meaningful without JavaScript
- Include proper data types - Use
data-typefor numbers, booleans, and JSON - Structure list items correctly - Binding elements should be children of list items
- Test without JavaScript - Ensure content is accessible when JS is disabled
❌ Don'ts
- Don't SSR everything - Use for content that benefits from immediate rendering
- Don't modify SSR content - Let the framework handle state synchronization
- Don't mix rendering paradigms - Be consistent within each component
- Don't skip templates - SSR lists still need templates for dynamic additions
Edge Cases
0, and false are preserved correctly:
<span data-bind="count" data-type="number">0</span> → state.count = 0
<span data-bind="enabled" data-type="boolean">false</span> → state.enabled = false