A complete React static site
A full site whose pages are React-rendered at build time and hydrated in the browser: fast first paint (real HTML), full interactivity after hydration, and no runtime SSR server โ it's static files.
This page builds directly on Build a React App. Same project, same App.jsx,
same styles and markup config. Three changes turn the client-only SPA into a pre-rendered,
hydrated static site:
1. Swap scripts for reactor
Replace the SPA's scripts entry with a reactor entry. Everything else in the config โ
styles, markup, serve, watch โ stays exactly as it was:
{
"reactor": [
{
"component": "src/js/App.jsx",
"inject": "app_html",
"in": "src/js/app-hydrate.jsx",
"out": "dist/js/app-hydrate.js",
"options": { "minify": true, "target": "es2019" }
}
]
}
component is rendered to HTML at build time; the result is exposed to templates as app_html.
in/out bundle the client entry that hydrates it. Full option reference in
React โบ Build-time pre-rendering.
2. Hydrate instead of mount
The SPA's main.tsx called createRoot. Here the client entry hydrates the HTML that is
already on the page:
// src/js/app-hydrate.jsx
import { hydrateRoot } from 'react-dom/client'
import App from './App.jsx'
hydrateRoot(document.getElementById('root'), <App />)
3. Inject the rendered HTML
The SPA shipped an empty <div id="root">. Now the template drops the build-time HTML into it,
then loads the hydration bundle:
{% extends "default.html" %}
{% block content %}
<div id="root">{{ app_html | safe }}</div>
<script src="{{ relativePathPrefix }}js/app-hydrate.min.js"></script>
{% endblock %}
How the build flows
- Poops bundles
App.jsxwithreact-dom/server, callsrenderToString, stores the HTML asapp_html. - Markup renders
index.html, injectingapp_htmlinto#root. app-hydrate.jsxis bundled todist/js/app-hydrate.min.js.- In the browser, React hydrates the pre-rendered HTML โ the page is interactive.
Tip
This gives you SSG with hydration and no separate server. Deploy the dist/ folder to any
static host (GitHub Pages, Netlify, S3).
Warning
The server-rendered markup and the client's first render must match, or React logs a hydration
mismatch. Keep App.jsx deterministic at build time โ no Date.now(), Math.random() or
browser-only APIs during the initial render.
Full runnable examples live in the Poops repository's example/ directory (react.html and
react-client.html).