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

Code before:
      export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
      export const ssr = ${ctx.reactRouterConfig.ssr};
      export const isSpaMode = ${isSpaMode};
      export const prerender = ${JSON.stringify(prerenderPaths)};
      export const publicPath = ${JSON.stringify(ctx.publicPath)};
      export const entry = { module: entryServer };
      export const routes = {
        ${Object.keys(routes)
          .map((key, index) => {
            let route = routes[key]!;
            return `${JSON.stringify(key)}: {
          id: ${JSON.stringify(route.id)},
          parentId: ${JSON.stringify(route.parentId)},
          path: ${JSON.stringify(route.path)},
          index: ${JSON.stringify(route.index)},
          caseSensitive: ${JSON.stringify(route.caseSensitive)},
          module: route${index}
        }`;
          })
          .join(",\n  ")}
      };
      ${
        ctx.reactRouterConfig.future.unstable_viteEnvironmentApi &&
        viteCommand === "serve"
          ? `
              export const getCriticalCss = ({ pathname }) => {
                return {
                  rel: "stylesheet",
                  href: "${
                    viteUserConfig.base ?? "/"
                  }@react-router/critical.css?pathname=" + pathname,
                };
              }
            `
          : ""
      }`;
  };

  let loadViteManifest = async (directory: string) => {
    let manifestContents = await fse.readFile(
      path.resolve(directory, ".vite", "manifest.json"),
      "utf-8"
    );
    return JSON.parse(manifestContents) as Vite.Manifest;
  };

  let hasDependency = (name: string) => {
    try {
      return Boolean(require.resolve(name, { paths: [ctx.rootDirectory] }));
    } catch (err) {
      return false;

Review comment (suggestion):
Seeing this API in a new light as part of this PR made me realise this should be marked as unstable. It was only ever defined when setting the `future.unstable_viteEnvironmentApi` flag.

Code after:
      export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
      export const ssr = ${ctx.reactRouterConfig.ssr};
      export const isSpaMode = ${isSpaMode};
      export const prerender = ${JSON.stringify(prerenderPaths)};
      export const publicPath = ${JSON.stringify(ctx.publicPath)};
      export const entry = { module: entryServer };
      export const routes = {
        ${Object.keys(routes)
          .map((key, index) => {
            let route = routes[key]!;
            return `${JSON.stringify(key)}: {
          id: ${JSON.stringify(route.id)},
          parentId: ${JSON.stringify(route.parentId)},
          path: ${JSON.stringify(route.path)},
          index: ${JSON.stringify(route.index)},
          caseSensitive: ${JSON.stringify(route.caseSensitive)},
          module: route${index}
        }`;
          })
          .join(",\n  ")}
      };
      ${
        ctx.reactRouterConfig.future.unstable_viteEnvironmentApi &&
        viteCommand === "serve"
          ? `
              export const unstable_getCriticalCss = ({ pathname }) => {
                return {
                  rel: "stylesheet",
                  href: "${
                    viteUserConfig.base ?? "/"
                  }@react-router/critical.css?pathname=" + pathname,
                };
              }
            `
          : ""
      }`;
  };

  let loadViteManifest = async (directory: string) => {
    let manifestContents = await fse.readFile(
      path.resolve(directory, ".vite", "manifest.json"),
      "utf-8"
    );
    return JSON.parse(manifestContents) as Vite.Manifest;
  };

  let hasDependency = (name: string) => {
    try {
      return Boolean(require.resolve(name, { paths: [ctx.rootDirectory] }));
    } catch (err) {
      return false;