Repository: remix-run/react-router
File: packages/react-router-dev/vite/plugin.ts (TypeScript)

Code before:

  // Write out the .data file
  let outdir = path.relative(process.cwd(), clientBuildDirectory);
  let outfile = path.join(outdir, ...normalizedPath.split("/"));
  await fse.ensureDir(path.dirname(outfile));
  await fse.outputFile(outfile, data);
  viteConfig.logger.info(`Prerender: Generated ${colors.bold(outfile)}`);
}

async function prerenderRoute(
  handler: RequestHandler,
  prerenderPath: string,
  clientBuildDirectory: string,
  reactRouterConfig: Awaited<ReturnType<typeof resolveReactRouterConfig>>,
  viteConfig: Vite.ResolvedConfig,
  requestInit: RequestInit
) {
  let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(
    /\/\/+/g,
    "/"
  );
  let request = new Request(`http://localhost${normalizedPath}`, requestInit);
  let response = await handler(request);
  let html = await response.text();

  validatePrerenderedResponse(response, html, "Prerender", normalizedPath);

  if (!reactRouterConfig.ssr) {
    validatePrerenderedHtml(html, "Prerender");
  }

  // Write out the HTML file
  let outdir = path.relative(process.cwd(), clientBuildDirectory);
  let outfile = path.join(outdir, ...normalizedPath.split("/"), "index.html");
  await fse.ensureDir(path.dirname(outfile));
  await fse.outputFile(outfile, html);
  viteConfig.logger.info(`Prerender: Generated ${colors.bold(outfile)}`);
}

async function prerenderManifest(
  build: ServerBuild,
  clientBuildDirectory: string,
  reactRouterConfig: Awaited<ReturnType<typeof resolveReactRouterConfig>>,
  viteConfig: Vite.ResolvedConfig
) {
  let normalizedPath = `${reactRouterConfig.basename}/__manifest`.replace(
    /\/\/+/g,
    "/"
  );
  let outdir = path.relative(process.cwd(), clientBuildDirectory);
  let outfile = path.join(outdir, ...normalizedPath.split("/"));

Review comment (suggestion):
With fog of war we now should prerender the `__manifest` as well.  This means that statically prerendered sites will load the _full_ manifest on initial load since there's no way to dynamically fetch based on the query params for only outgoing routes - and the enumerations aren't possible to prerender single-request manifest patches.

The only thing I can think of to enable true "fog of war" with prerendering would be to generate a `.manifest` file per path (like we do for `.data`) and then instead of one request to `__manifest` we'd load one request per outgoing path - but that would be be sub-optimal because pages with many links would end many request in parallel.

I think maybe the way to go is when pre-rendering is enabled - disable the "outgoing links" discovery and just let the first link click load the full `__manifest` and then all subsequent links clicks would match syncronously.

Code after:
    if (hasLoaders) {
      await prerenderData(
        handler,
        path,
        clientBuildDirectory,
        reactRouterConfig,
        viteConfig,
        requestInit
      );
    }
    await prerenderRoute(
      handler,
      path,
      clientBuildDirectory,
      reactRouterConfig,
      viteConfig,
      requestInit
    );
  }

  await prerenderManifest(
    build,
    clientBuildDirectory,
    reactRouterConfig,
    viteConfig
  );
}

function determineStaticPrerenderRoutes(
  routes: DataRouteObject[],
  viteConfig: Vite.ResolvedConfig,
  isBooleanUsage = false
): string[] {
  // Always start with the root/index route included
  let paths: string[] = ["/"];
  let paramRoutes: string[] = [];

  // Then recursively add any new path defined by the tree
  function recurse(subtree: typeof routes, prefix = "") {
    for (let route of subtree) {
      let newPath = [prefix, route.path].join("/").replace(/\/\/+/g, "/");
      if (route.path) {
        let segments = route.path.split("/");
        if (segments.some((s) => s.startsWith(":") || s === "*")) {
          paramRoutes.push(route.path);
        } else {
          paths.push(newPath);
        }
      }
      if (route.children) {
        recurse(route.children, newPath);