Server-Side Rendering
@whisq/ssr lets you render Whisq components to HTML strings on the server. The browser receives pre-rendered HTML, then Whisq hydrates it into an interactive app on the client.
Install the SSR package:
npm install @whisq/ssrBasic Server Rendering
Section titled “Basic Server Rendering”Use renderToString() to convert a component tree to HTML:
import { renderToString } from "@whisq/ssr";import { div, h1, p, ul, li } from "@whisq/core";
const Page = () => div( h1("Welcome"), p("This page was rendered on the server."), ul( li("Fast initial load"), li("SEO friendly"), li("Works without JavaScript"), ), );
const html = renderToString(Page());// <div><h1>Welcome</h1><p>This page was rendered on the server.</p>...</div>Express Server Example
Section titled “Express Server Example”Serve a Whisq app from an Express server:
import express from "express";import { renderToString } from "@whisq/ssr";import { component, div, h1, p } from "@whisq/core";
const App = component(() => div( h1("My App"), p("Server-rendered with Whisq"), ));
const app = express();
app.get("*", (req, res) => { const content = renderToString(App({})); res.send(` <!DOCTYPE html> <html> <head><title>My App</title></head> <body> <div id="app">${content}</div> <script src="/client.js"></script> </body> </html> `);});
app.listen(3000);Hydration
Section titled “Hydration”On the client, call mount() on the same root element. Whisq attaches event handlers to the existing HTML:
import { mount } from "@whisq/core";import { App } from "./app";
mount(App({}), document.getElementById("app"));The user sees the server-rendered content immediately, and interactivity kicks in once the client JavaScript loads.
How It Works
Section titled “How It Works”- Reactive values are evaluated once — signals are read at render time and their current value is used in the HTML output.
- Event handlers are stripped —
onclick,oninput, etc. don’t appear in the server HTML. They’re attached during hydration. - HTML is properly escaped — attribute values and text content are escaped to prevent XSS.
When to Use SSR
Section titled “When to Use SSR”| Use SSR when… | Use client-only when… |
|---|---|
| SEO matters (public pages, blogs) | App is behind a login |
| Fast first paint is critical | Content is fully dynamic |
| Users have slow connections | App is a dashboard or tool |
| Content doesn’t change per-user | Real-time data is the focus |
Rendering with Data
Section titled “Rendering with Data”Fetch data on the server before rendering:
app.get("/users", async (req, res) => { const users = await fetch("https://api.example.com/users") .then(r => r.json());
const Page = () => div( h1("Users"), ul(users.map(u => li(u.name))), );
const html = renderToString(Page()); res.send(wrapInShell(html));});Next Steps
Section titled “Next Steps”- Routing — Server-render different pages based on URL
- Data Fetching — Client-side data loading after hydration
- Testing — Test server-rendered output