Hydration
After the server generates static HTML, the browser needs to "wake it up" — reconnecting event listeners, reactive Cells, and making the page interactive. This process is called hydration.
Basic Setup
In your client-side entry point, import hydrate from retend-server/client and pass it your router factory function:
// source/main.ts import { hydrate } from 'retend-server/client'; import { createRouter } from './router'; hydrate(createRouter);
The hydrate function:
- Finds the existing server-rendered HTML.
- Re-creates the router and matches the current URL.
- Attaches event listeners and reactive bindings to the existing elements.
- Dispatches a
hydrationcompletedevent onwindowwhen finished.
window.addEventListener('hydrationcompleted', () => { console.log('App is now interactive!'); });
Options
The hydrate function accepts an options object as its second argument:
hydrate(createRouter, { rootId: 'app', wrap(root) { return root; }, });
| Option | Default | Description |
|---|---|---|
rootId | "app" | The id of the root element that holds the server-rendered HTML. |
wrap | — | A function that wraps the app root before rendering. Useful for adding global providers. |
Wrapping the App
If your app needs a global provider (like a theme or auth context) that wraps the entire router, use the wrap option:
import { ThemeScope } from './scopes'; hydrate(createRouter, { wrap(root) { return <ThemeScope.Provider value="dark">{root}</ThemeScope.Provider>; }, });
Development Mode
In development, hydrate behaves differently. Since there's no pre-rendered HTML during vite dev, it falls back to normal client-side rendering (SPA mode). This means you can use the same entry point for both development and production without any conditional logic.
If the server context script tag (<script data-server-context>) is missing when running in production, hydrate logs a warning and falls back to SPA mode automatically.