Skip to content

Instantly share code, notes, and snippets.

@agoose77
Created September 17, 2026 21:22
Show Gist options
  • Select an option

  • Save agoose77/d6452710857fbada084e0385daf47cc3 to your computer and use it in GitHub Desktop.

Select an option

Save agoose77/d6452710857fbada084e0385daf47cc3 to your computer and use it in GitHub Desktop.
import * as fsp from "node:fs/promises";
import * as path from "node:path";
import { createRequestHandler } from "react-router";
import * as build from "virtual:react-router/server-build";
const MAGIC_BASE_URL = build.basename;
const TRUE_BASE_URL = process.env.BASE_URL ?? "/";
const PRERENDER_PATHS = [`${MAGIC_BASE_URL}`, `${MAGIC_BASE_URL}parent/about/`];
const DATA_HEADER = "X-React-Router-Prerender-Data";
process.env.IS_RR_BUILD_REQUEST = "yes";
const handler = createRequestHandler(build, "production");
const clientPath = path.join("./build", "client");
const assetsPath = path.join(clientPath, "assets");
/**
* Substitute the magic placeholder base URL with the expected one
*/
const rewriteContent = (content: string): string => {
return content.replaceAll(MAGIC_BASE_URL, TRUE_BASE_URL);
};
const rewriteAssets = async () => {
for await (const entry of fsp.glob(["**/*.js", "**/*.html", "**/*.css"], {
cwd: assetsPath,
})) {
const assetPath = path.join(assetsPath, entry);
const source = await fsp.readFile(assetPath, { encoding: "utf-8" });
await fsp.writeFile(assetPath, rewriteContent(source), {
encoding: "utf-8",
});
console.log(entry);
}
};
const renderRoute = async (prerenderPath: string) => {
// You can do things concurrnetly if you'd like
let dataRequestPath = prerenderPath.endsWith("/")
? `${prerenderPath}_.data`
: `${prerenderPath}.data`;
const dataURL = new URL(dataRequestPath, "http://pre.render");
const dataResponse = await handler(new Request(dataURL));
const data = await dataResponse.text();
if (!dataResponse.ok) {
throw new Error(
`Invalid data response for ${prerenderPath}: ${dataResponse.status}`,
);
}
const htmlURL = new URL(prerenderPath, "http://pre.render");
const htmlResponse = await handler(
new Request(htmlURL, {
headers: {
[DATA_HEADER]: data,
},
}),
);
const html = await htmlResponse.text();
if (!htmlResponse.ok) {
throw new Error(
`Invalid html response for ${prerenderPath}: ${dataResponse.status}`,
);
}
if (!prerenderPath.startsWith(MAGIC_BASE_URL)) {
throw new Error(
"Invalid prerender path: expected URL to start with (magic) base URL",
);
}
// Drop /foo of /foo/ → /
const destPrerenderPath = prerenderPath.slice(MAGIC_BASE_URL.length - 1);
const htmlFilepath = path.resolve(
path.join(
clientPath,
...(destPrerenderPath + "/index.html").split("/").filter(Boolean),
),
);
await fsp.mkdir(path.dirname(htmlFilepath), { recursive: true });
await fsp.writeFile(htmlFilepath, rewriteContent(html), "utf-8");
};
await Promise.all([
...PRERENDER_PATHS.map((p) => renderRoute(p)),
rewriteAssets(),
]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment