Created
September 17, 2026 21:22
-
-
Save agoose77/d6452710857fbada084e0385daf47cc3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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