Static & ISR Engines
Understand the static route crawlers, background SWR revalidation engines, and programmatic cache invalidation APIs that run inside the framework core.
Key Files Involved:1. Crawling & Evaluation
build-static-pages.js: Crawls routes and evaluates static/dynamic status.get-ssg-metadata.js: Resolves side-effect cookies/redirects.2. Orchestrators & Triggers
generate-static.js: Bulk startup pre-generation entry point.revalidating.js: Background ISR expiration revalidator.generating-isg.js: On-demand dynamic route ISG compiler.cache-revalidate.js: Programmatic path & tag revalidation API.3. RSC & HTML Generators
generate-static-rsc.js: Generates single-route RSC payload.generate-static-rscs.js: Generates bulk-route RSC payloads.generate-static-page.js: Renders single-route HTML files.generate-static-pages.js: Renders bulk-route HTML files.4. Utilities & State
safe-rename.js: Atomic retry committer for safe disk writes.status-manifest.js: Tracks and synchronizes routing state.
💡 Overview
Dinou provides four rendering and caching patterns for pages:
- Static Site Generation (SSG): Pages are pre-rendered during production server startup and served instantly from disk.
- Incremental Static Regeneration (ISR): Expired pages are re-generated asynchronously in the background upon client requests.
- Incremental Static Generation (ISG): Dynamic parameter routes not resolved at startup are rendered on their first request and cached immediately.
- On-Demand Revalidation: Specific routes or tag-matched sets are purged and rebuilt immediately using programmatic API calls (such as inside Server Functions or Express endpoints).
💾 1. SSG Static Builder (build-static-pages.js)
When the production server starts up, it runs the static page crawler script:
// Bulk startup orchestration flow inside generate-static.js
async function generateStatic() {
// 1. Crawl filesystem and resolve static/dynamic configurations
await buildStaticPages();
const routes = getStaticPaths();
// 2. Generate and write all RSC flight payload files (.rsc) in parallel
await generateStaticRSCs(routes);
// 3. Render and write all static HTML files (index.html) in bulk
await generateStaticPages(routes);
}It iterates through crawled paths, evaluates the Server Components tree, outputs the RSC Flight payload, and triggers the child process renderer to compile the final static HTML. If a page calls dynamic features (like reading request headers), the builder detects the bailout and skips writing.
🔄 2. Background Revalidation (revalidating.js)
When a user visits a stale cached route, Dinou serves the current cached file immediately (Stale-While-Revalidate) and triggers a background regeneration hook:
const regenerating = new Set(); // Execution mutex locks
function revalidating(reqPath, isDynamicFromServer) {
if (regenerating.has(reqPath)) return; // Avoid concurrent compile conflicts
fs.readFile(metadataPath, "utf8").then((content) => {
const { revalidate, generatedAt } = JSON.parse(content);
const isExpired = Date.now() > generatedAt + revalidate;
if (isExpired) {
// Serve stale files while compiling
copyFileSync("index.html", "index._old.html");
copyFileSync("rsc.rsc", "rsc._old.rsc");
regenerating.add(reqPath); // Acquire compile lock
(async () => {
try {
const isDynamic = {};
await buildStaticPage(reqPath, isDynamic);
if (isDynamic.value) {
isDynamicFromServer.value = true;
return;
}
const rscResult = await generateStaticRSC(reqPath);
await safeRename(rscResult.tempPath, rscResult.finalPath);
const pageResult = await generateStaticPage(reqPath);
await safeRename(pageResult.tempPath, pageResult.finalPath);
updateStatus(reqPath, pageResult.status);
} finally {
regenerating.delete(reqPath); // Release lock
}
})();
}
});
}The regenerating set is a lock that blocks subsequent requests from starting parallel build forks for the same page, preventing server overload.
⚡ 3. On-Demand Revalidation (cache-revalidate.js)
Dinou provides an API endpoint to purge and rebuild cached routes immediately (e.g., when a headless CMS webhook fires). Calling revalidatePath(path):
async function revalidatePath(reqPath) {
const cleanPath = normalizeRoutePath(reqPath);
// 1. Back up current pages to old
backupStaleFiles(cleanPath);
// 2. Re-render and write updated files
const isDynamic = {};
await buildStaticPage(cleanPath, isDynamic);
if (isDynamic.value) return;
const rscResult = await generateStaticRSC(cleanPath);
await safeRename(rscResult.tempPath, rscResult.finalPath);
const pageResult = await generateStaticPage(cleanPath);
await safeRename(pageResult.tempPath, pageResult.finalPath);
updateStatus(cleanPath, pageResult.status);
}Unlike background ISR (which triggers on browser visits), on-demand revalidation rebuilds resources immediately, ensuring users see CMS updates instantly.
🚀 4. Dynamic Pre-render (generating-isg.js)
When you request a route that doesn't exist at build time, the server triggers the ISG engine:
- Checks if the path matches a dynamic route template (e.g.
/posts/[id]). - Forks a compilation task to evaluate the layout and dynamic params.
- Generates and commits the
rsc.rscandindex.htmlfiles dynamically to the disk cache. - Subsequent visits bypass compilation entirely and serve the cached static file directly.
⏱️ 5. Stale-While-Revalidate Lifecycle
The diagram below outlines the cache check and background regeneration flow:
🛠️ Common Tweak Recipes
You can override revalidation intervals globally or per route pattern by adjusting metadata properties generated inside core/build-static-pages.js.
By default, Dinou writes cache files to the server's disk space. You can redirect these checks by replacing file read/write operations (fs.readFile, fs.writeFile) in core/revalidating.js with Redis or S3 client connections.