@react-router/dev 0.0.0-experimental-a383e1e6e → 0.0.0-experimental-b9cf540fe

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vite.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-a383e1e6e
2
+ * @react-router/dev v0.0.0-experimental-b9cf540fe
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -52,6 +52,7 @@ var fse = __toESM(require("fs-extra"));
52
52
  var babel = __toESM(require("@babel/core"));
53
53
  var import_react_router2 = require("react-router");
54
54
  var import_es_module_lexer = require("es-module-lexer");
55
+ var import_pick3 = __toESM(require("lodash/pick"));
55
56
  var import_jsesc = __toESM(require("jsesc"));
56
57
  var import_picocolors3 = __toESM(require("picocolors"));
57
58
  var import_kebabCase = __toESM(require("lodash/kebabCase"));
@@ -271,6 +272,13 @@ var detectPackageManager = () => {
271
272
 
272
273
  // config/config.ts
273
274
  var excludedConfigPresetKeys = ["presets"];
275
+ var branchRouteProperties = [
276
+ "id",
277
+ "path",
278
+ "file",
279
+ "index"
280
+ ];
281
+ var configRouteToBranchRoute = (configRoute) => (0, import_pick2.default)(configRoute, branchRouteProperties);
274
282
  var mergeReactRouterConfig = (...configs) => {
275
283
  let reducer = (configA, configB) => {
276
284
  let mergeRequired = (key) => configA[key] !== void 0 && configB[key] !== void 0;
@@ -694,8 +702,6 @@ function generate(ctx, route) {
694
702
  export type HeadersArgs = T.HeadersArgs
695
703
  export type HeadersFunction = (args: HeadersArgs) => Headers | HeadersInit
696
704
 
697
- export type unstable_MiddlewareArgs = T.CreateServerMiddlewareArgs<Info>
698
- export type unstable_ClientMiddlewareArgs = T.CreateClientMiddlewareArgs<Info>
699
705
  export type LoaderArgs = T.CreateServerLoaderArgs<Info>
700
706
  export type ClientLoaderArgs = T.CreateClientLoaderArgs<Info>
701
707
  export type ActionArgs = T.CreateServerActionArgs<Info>
@@ -1800,6 +1806,8 @@ var plugin = {
1800
1806
  return function Wrapped() {
1801
1807
  const props = {
1802
1808
  params: useParams(),
1809
+ loaderData: useLoaderData(),
1810
+ actionData: useActionData(),
1803
1811
  };
1804
1812
  return h(HydrateFallback, props);
1805
1813
  };
@@ -1893,27 +1901,18 @@ function toFunctionExpression(decl) {
1893
1901
  }
1894
1902
 
1895
1903
  // vite/plugin.ts
1896
- var SERVER_ONLY_ROUTE_EXPORTS = [
1897
- "loader",
1898
- "action",
1899
- "unstable_middleware",
1900
- "headers"
1901
- ];
1902
- var CLIENT_ONLY_NON_COMPONENT_EXPORTS = [
1904
+ var SERVER_ONLY_ROUTE_EXPORTS = ["loader", "action", "headers"];
1905
+ var CLIENT_ROUTE_EXPORTS = [
1903
1906
  "clientAction",
1904
1907
  "clientLoader",
1905
- "unstable_clientMiddleware",
1906
- "handle",
1907
- "meta",
1908
- "links",
1909
- "shouldRevalidate"
1910
- ];
1911
- var CLIENT_ROUTE_EXPORTS = [
1912
- ...CLIENT_ONLY_NON_COMPONENT_EXPORTS,
1913
1908
  "default",
1914
1909
  "ErrorBoundary",
1910
+ "handle",
1915
1911
  "HydrateFallback",
1916
- "Layout"
1912
+ "Layout",
1913
+ "links",
1914
+ "meta",
1915
+ "shouldRevalidate"
1917
1916
  ];
1918
1917
  var BUILD_CLIENT_ROUTE_QUERY_STRING = "?__react-router-build-client-route";
1919
1918
  var isRouteEntryModuleId = (id) => {
@@ -2074,16 +2073,24 @@ var getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteF
2074
2073
  );
2075
2074
  return getExportNames(code);
2076
2075
  };
2077
- var getServerBundleBuildConfig = (viteUserConfig) => {
2078
- if (!("__reactRouterServerBundleBuildConfig" in viteUserConfig) || !viteUserConfig.__reactRouterServerBundleBuildConfig) {
2076
+ var resolveEnvironmentBuildContext = ({
2077
+ viteCommand,
2078
+ viteUserConfig
2079
+ }) => {
2080
+ if (!("__reactRouterEnvironmentBuildContext" in viteUserConfig) || !viteUserConfig.__reactRouterEnvironmentBuildContext) {
2079
2081
  return null;
2080
2082
  }
2081
- return viteUserConfig.__reactRouterServerBundleBuildConfig;
2083
+ let buildContext = viteUserConfig.__reactRouterEnvironmentBuildContext;
2084
+ let resolvedBuildContext = {
2085
+ name: buildContext.name,
2086
+ options: buildContext.resolveOptions({ viteCommand, viteUserConfig })
2087
+ };
2088
+ return resolvedBuildContext;
2082
2089
  };
2083
- var getServerBuildDirectory = (ctx) => path6.join(
2090
+ var getServerBuildDirectory = (ctx, { serverBundleId } = {}) => path6.join(
2084
2091
  ctx.reactRouterConfig.buildDirectory,
2085
2092
  "server",
2086
- ...ctx.serverBundleBuildConfig ? [ctx.serverBundleBuildConfig.serverBundleId] : []
2093
+ ...serverBundleId ? [serverBundleId] : []
2087
2094
  );
2088
2095
  var getClientBuildDirectory = (reactRouterConfig) => path6.join(reactRouterConfig.buildDirectory, "client");
2089
2096
  var defaultEntriesDir = path6.resolve(
@@ -2135,36 +2142,37 @@ var reactRouterVitePlugin = () => {
2135
2142
  process.exit(1);
2136
2143
  }
2137
2144
  let viteManifestEnabled = viteUserConfig.build?.manifest === true;
2138
- let ssrBuildCtx = viteConfigEnv.isSsrBuild && viteCommand === "build" ? {
2139
- isSsrBuild: true,
2140
- getReactRouterServerManifest: async () => (await generateReactRouterManifestsForBuild()).reactRouterServerManifest,
2141
- serverBundleBuildConfig: getServerBundleBuildConfig(viteUserConfig)
2142
- } : { isSsrBuild: false };
2145
+ let environmentBuildContext = viteCommand === "build" ? resolveEnvironmentBuildContext({ viteCommand, viteUserConfig }) : null;
2143
2146
  firstLoad = false;
2144
2147
  ctx = {
2148
+ environmentBuildContext,
2145
2149
  reactRouterConfig,
2146
2150
  rootDirectory,
2147
2151
  entryClientFilePath,
2148
2152
  entryServerFilePath,
2149
2153
  publicPath,
2150
- viteManifestEnabled,
2151
- ...ssrBuildCtx
2154
+ viteManifestEnabled
2152
2155
  };
2153
2156
  };
2154
2157
  let pluginIndex = (pluginName) => {
2155
2158
  invariant(viteConfig);
2156
2159
  return viteConfig.plugins.findIndex((plugin2) => plugin2.name === pluginName);
2157
2160
  };
2158
- let getServerEntry = async () => {
2161
+ let getServerEntry = async ({ routeIds }) => {
2159
2162
  invariant(viteConfig, "viteconfig required to generate the server entry");
2160
- let routes = ctx.serverBundleBuildConfig ? (
2163
+ let routes = routeIds ? (
2161
2164
  // For server bundle builds, the server build should only import the
2162
2165
  // routes for this bundle rather than importing all routes
2163
- ctx.serverBundleBuildConfig.routes
2166
+ (0, import_pick3.default)(ctx.reactRouterConfig.routes, routeIds)
2164
2167
  ) : (
2165
2168
  // Otherwise, all routes are imported as usual
2166
2169
  ctx.reactRouterConfig.routes
2167
2170
  );
2171
+ let prerenderPaths = await getPrerenderPaths(
2172
+ ctx.reactRouterConfig.prerender,
2173
+ ctx.reactRouterConfig.ssr,
2174
+ routes
2175
+ );
2168
2176
  return `
2169
2177
  import * as entryServer from ${JSON.stringify(
2170
2178
  resolveFileUrl(ctx, ctx.entryServerFilePath)
@@ -2179,7 +2187,7 @@ var reactRouterVitePlugin = () => {
2179
2187
  )};`;
2180
2188
  }).join("\n")}
2181
2189
  export { default as assets } from ${JSON.stringify(
2182
- virtual.serverManifest.id
2190
+ `${virtual.serverManifest.id}${routeIds ? `?route-ids=${routeIds.join(",")}` : ""}`
2183
2191
  )};
2184
2192
  export const assetsBuildDirectory = ${JSON.stringify(
2185
2193
  path6.relative(
@@ -2191,6 +2199,7 @@ var reactRouterVitePlugin = () => {
2191
2199
  export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
2192
2200
  export const ssr = ${ctx.reactRouterConfig.ssr};
2193
2201
  export const isSpaMode = ${isSpaModeEnabled(ctx.reactRouterConfig)};
2202
+ export const prerender = ${JSON.stringify(prerenderPaths)};
2194
2203
  export const publicPath = ${JSON.stringify(ctx.publicPath)};
2195
2204
  export const entry = { module: entryServer };
2196
2205
  export const routes = {
@@ -2228,7 +2237,9 @@ var reactRouterVitePlugin = () => {
2228
2237
  );
2229
2238
  return /* @__PURE__ */ new Set([...cssUrlPaths, ...chunkAssetPaths]);
2230
2239
  };
2231
- let generateReactRouterManifestsForBuild = async () => {
2240
+ let generateReactRouterManifestsForBuild = async ({
2241
+ routeIds
2242
+ }) => {
2232
2243
  invariant(viteConfig);
2233
2244
  let viteManifest = await loadViteManifest(
2234
2245
  getClientBuildDirectory(ctx.reactRouterConfig)
@@ -2245,9 +2256,9 @@ var reactRouterVitePlugin = () => {
2245
2256
  ctx
2246
2257
  );
2247
2258
  let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
2248
- for (let [key, route] of Object.entries(ctx.reactRouterConfig.routes)) {
2259
+ for (let route of Object.values(ctx.reactRouterConfig.routes)) {
2249
2260
  let routeFile = path6.join(ctx.reactRouterConfig.appDirectory, route.file);
2250
- let sourceExports = routeManifestExports[key];
2261
+ let sourceExports = routeManifestExports[route.id];
2251
2262
  let isRootRoute = route.parentId === void 0;
2252
2263
  let hasClientAction = sourceExports.includes("clientAction");
2253
2264
  let hasClientLoader = sourceExports.includes("clientLoader");
@@ -2305,10 +2316,9 @@ var reactRouterVitePlugin = () => {
2305
2316
  getRouteChunkModuleId(routeFile, "HydrateFallback")
2306
2317
  ) : void 0
2307
2318
  };
2308
- browserRoutes[key] = routeManifestEntry;
2309
- let serverBundleRoutes = ctx.serverBundleBuildConfig?.routes;
2310
- if (!serverBundleRoutes || serverBundleRoutes[key]) {
2311
- serverRoutes[key] = routeManifestEntry;
2319
+ browserRoutes[route.id] = routeManifestEntry;
2320
+ if (!routeIds || routeIds.includes(route.id)) {
2321
+ serverRoutes[route.id] = routeManifestEntry;
2312
2322
  }
2313
2323
  }
2314
2324
  let fingerprintedValues = { entry, routes: browserRoutes };
@@ -2456,23 +2466,6 @@ var reactRouterVitePlugin = () => {
2456
2466
  ""
2457
2467
  )
2458
2468
  );
2459
- let baseRollupOptions = {
2460
- // Silence Rollup "use client" warnings
2461
- // Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
2462
- onwarn(warning, defaultHandler) {
2463
- if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
2464
- return;
2465
- }
2466
- if (viteUserConfig.build?.rollupOptions?.onwarn) {
2467
- viteUserConfig.build.rollupOptions.onwarn(
2468
- warning,
2469
- defaultHandler
2470
- );
2471
- } else {
2472
- defaultHandler(warning);
2473
- }
2474
- }
2475
- };
2476
2469
  return {
2477
2470
  __reactRouterPluginContext: ctx,
2478
2471
  appType: viteCommand === "serve" && viteConfigEnv.mode === "production" && ctx.reactRouterConfig.ssr === false ? "spa" : "custom",
@@ -2530,83 +2523,11 @@ var reactRouterVitePlugin = () => {
2530
2523
  // will throw an error that the file is not allowed to be read.
2531
2524
  // https://vitejs.dev/config/server-options#server-fs-allow
2532
2525
  server: viteUserConfig.server?.fs?.allow ? { fs: { allow: defaultEntries } } : void 0,
2533
- // Vite config options for building
2534
- ...viteCommand === "build" ? {
2535
- build: {
2536
- cssMinify: viteUserConfig.build?.cssMinify ?? true,
2537
- ...!viteConfigEnv.isSsrBuild ? {
2538
- manifest: true,
2539
- outDir: getClientBuildDirectory(ctx.reactRouterConfig),
2540
- rollupOptions: {
2541
- ...baseRollupOptions,
2542
- preserveEntrySignatures: "exports-only",
2543
- output: {
2544
- entryFileNames({ moduleIds }) {
2545
- let routeChunkModuleId = moduleIds.find(isRouteChunkModuleId);
2546
- let routeChunkName = routeChunkModuleId ? getRouteChunkNameFromModuleId(
2547
- routeChunkModuleId
2548
- ) : null;
2549
- let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
2550
- return `assets/[name]${routeChunkSuffix}-[hash].js`;
2551
- }
2552
- },
2553
- input: [
2554
- ctx.entryClientFilePath,
2555
- ...Object.values(
2556
- ctx.reactRouterConfig.routes
2557
- ).flatMap((route) => {
2558
- let routeFilePath = path6.resolve(
2559
- ctx.reactRouterConfig.appDirectory,
2560
- route.file
2561
- );
2562
- let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
2563
- let code = fse.readFileSync(
2564
- routeFilePath,
2565
- "utf-8"
2566
- );
2567
- return [
2568
- `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
2569
- ...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
2570
- (exportName) => code.includes(exportName) ? getRouteChunkModuleId(
2571
- routeFilePath,
2572
- exportName
2573
- ) : null
2574
- ) : []
2575
- ].filter(isNonNullable);
2576
- })
2577
- ]
2578
- }
2579
- } : {
2580
- // We move SSR-only assets to client assets. Note that the
2581
- // SSR build can also emit code-split JS files (e.g. by
2582
- // dynamic import) under the same assets directory
2583
- // regardless of "ssrEmitAssets" option, so we also need to
2584
- // keep these JS files have to be kept as-is.
2585
- ssrEmitAssets: true,
2586
- copyPublicDir: false,
2587
- // Assets in the public directory are only used by the client
2588
- manifest: true,
2589
- // We need the manifest to detect SSR-only assets
2590
- outDir: getServerBuildDirectory(ctx),
2591
- rollupOptions: {
2592
- ...baseRollupOptions,
2593
- preserveEntrySignatures: "exports-only",
2594
- input: viteUserConfig.build?.rollupOptions?.input ?? virtual.serverBuild.id,
2595
- output: {
2596
- entryFileNames: ctx.reactRouterConfig.serverBuildFile,
2597
- format: ctx.reactRouterConfig.serverModuleFormat
2598
- }
2599
- }
2600
- }
2601
- }
2602
- } : void 0,
2603
- // Vite config options for SPA preview mode
2604
- ...viteCommand === "serve" && ctx.reactRouterConfig.ssr === false ? {
2605
- build: {
2606
- manifest: true,
2607
- outDir: getClientBuildDirectory(ctx.reactRouterConfig)
2608
- }
2609
- } : void 0
2526
+ build: ctx.environmentBuildContext?.options.build ?? (await getEnvironmentOptions(
2527
+ ctx,
2528
+ viteConfigEnv.isSsrBuild ? "ssr" : "client",
2529
+ { viteCommand, viteUserConfig }
2530
+ )).build
2610
2531
  };
2611
2532
  },
2612
2533
  async configResolved(resolvedViteConfig) {
@@ -2622,8 +2543,7 @@ var reactRouterVitePlugin = () => {
2622
2543
  let childCompilerConfigFile = await vite2.loadConfigFromFile(
2623
2544
  {
2624
2545
  command: viteConfig.command,
2625
- mode: viteConfig.mode,
2626
- isSsrBuild: ctx.isSsrBuild
2546
+ mode: viteConfig.mode
2627
2547
  },
2628
2548
  viteConfig.configFile
2629
2549
  );
@@ -2765,14 +2685,14 @@ var reactRouterVitePlugin = () => {
2765
2685
  // After the SSR build is finished, we inspect the Vite manifest for
2766
2686
  // the SSR build and move server-only assets to client assets directory
2767
2687
  async handler() {
2768
- if (!ctx.isSsrBuild) {
2688
+ if (!viteConfigEnv.isSsrBuild) {
2769
2689
  return;
2770
2690
  }
2771
2691
  invariant(viteConfig);
2772
2692
  let clientBuildDirectory = getClientBuildDirectory(
2773
2693
  ctx.reactRouterConfig
2774
2694
  );
2775
- let serverBuildDirectory = getServerBuildDirectory(ctx);
2695
+ let serverBuildDirectory = ctx.environmentBuildContext?.options.build.outDir ?? getServerBuildDirectory(ctx);
2776
2696
  let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
2777
2697
  let ssrAssetPaths = getViteManifestAssetPaths(ssrViteManifest);
2778
2698
  let movedAssetPaths = [];
@@ -2806,7 +2726,7 @@ var reactRouterVitePlugin = () => {
2806
2726
  ].join("\n")
2807
2727
  );
2808
2728
  }
2809
- if (ctx.reactRouterConfig.prerender != null && ctx.reactRouterConfig.prerender !== false) {
2729
+ if (isPrerenderingEnabled(ctx.reactRouterConfig)) {
2810
2730
  await handlePrerender(
2811
2731
  viteConfig,
2812
2732
  ctx.reactRouterConfig,
@@ -2961,16 +2881,25 @@ var reactRouterVitePlugin = () => {
2961
2881
  name: "react-router:virtual-modules",
2962
2882
  enforce: "pre",
2963
2883
  resolveId(id) {
2964
- const vmod2 = Object.values(virtual).find((vmod3) => vmod3.id === id);
2965
- if (vmod2) return vmod2.resolvedId;
2884
+ let [baseId, queryString] = id.split("?");
2885
+ const vmod2 = Object.values(virtual).find((vmod3) => vmod3.id === baseId);
2886
+ if (vmod2)
2887
+ return vmod2.resolvedId + (queryString ? `?${queryString}` : "");
2966
2888
  },
2967
2889
  async load(id) {
2968
- switch (id) {
2890
+ let [baseId, queryString] = id.split("?");
2891
+ switch (baseId) {
2969
2892
  case virtual.serverBuild.resolvedId: {
2970
- return await getServerEntry();
2893
+ let searchParams = new URLSearchParams(queryString);
2894
+ let routeIds = searchParams.get("route-ids")?.split(",") || void 0;
2895
+ return await getServerEntry({ routeIds });
2971
2896
  }
2972
2897
  case virtual.serverManifest.resolvedId: {
2973
- let reactRouterManifest = ctx.isSsrBuild ? await ctx.getReactRouterServerManifest() : await getReactRouterManifestForDev();
2898
+ let searchParams = new URLSearchParams(queryString);
2899
+ let routeIds = searchParams.get("route-ids")?.split(",") || void 0;
2900
+ let reactRouterManifest = viteCommand === "build" ? (await generateReactRouterManifestsForBuild({
2901
+ routeIds
2902
+ })).reactRouterServerManifest : await getReactRouterManifestForDev();
2974
2903
  return `export default ${(0, import_jsesc.default)(reactRouterManifest, {
2975
2904
  es6: true
2976
2905
  })};`;
@@ -3071,12 +3000,15 @@ var reactRouterVitePlugin = () => {
3071
3000
  if (!route) return;
3072
3001
  if (!options?.ssr && isSpaModeEnabled(ctx.reactRouterConfig)) {
3073
3002
  let exportNames = getExportNames(code);
3074
- let serverOnlyExports = exportNames.filter(
3075
- (exp) => SERVER_ONLY_ROUTE_EXPORTS.includes(exp)
3076
- );
3003
+ let serverOnlyExports = exportNames.filter((exp) => {
3004
+ if (route.id === "root" && exp === "loader") {
3005
+ return false;
3006
+ }
3007
+ return SERVER_ONLY_ROUTE_EXPORTS.includes(exp);
3008
+ });
3077
3009
  if (serverOnlyExports.length > 0) {
3078
3010
  let str = serverOnlyExports.map((e) => `\`${e}\``).join(", ");
3079
- let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://remix.run/guides/spa-mode for more information.`;
3011
+ let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://reactrouter.com/how-to/spa for more information.`;
3080
3012
  throw Error(message);
3081
3013
  }
3082
3014
  if (route.id !== "root") {
@@ -3084,7 +3016,7 @@ var reactRouterVitePlugin = () => {
3084
3016
  (exp) => exp === "HydrateFallback"
3085
3017
  );
3086
3018
  if (hasHydrateFallback) {
3087
- let message = `SPA Mode: Invalid \`HydrateFallback\` export found in \`${route.file}\`. \`HydrateFallback\` is only permitted on the root route in SPA Mode. See https://remix.run/guides/spa-mode for more information.`;
3019
+ let message = `SPA Mode: Invalid \`HydrateFallback\` export found in \`${route.file}\`. \`HydrateFallback\` is only permitted on the root route in SPA Mode. See https://reactrouter.com/how-to/spa for more information.`;
3088
3020
  throw Error(message);
3089
3021
  }
3090
3022
  }
@@ -3271,7 +3203,14 @@ function uniqueNodes(nodes) {
3271
3203
  }
3272
3204
  function addRefreshWrapper(reactRouterConfig, code, id) {
3273
3205
  let route = getRoute(reactRouterConfig, id);
3274
- let acceptExports = route ? CLIENT_ONLY_NON_COMPONENT_EXPORTS : [];
3206
+ let acceptExports = route ? [
3207
+ "clientAction",
3208
+ "clientLoader",
3209
+ "handle",
3210
+ "meta",
3211
+ "links",
3212
+ "shouldRevalidate"
3213
+ ] : [];
3275
3214
  return REACT_REFRESH_HEADER.replaceAll("__SOURCE__", JSON.stringify(id)) + code + REACT_REFRESH_FOOTER.replaceAll("__SOURCE__", JSON.stringify(id)).replaceAll("__ACCEPT_EXPORTS__", JSON.stringify(acceptExports)).replaceAll("__ROUTE_ID__", JSON.stringify(route?.id));
3276
3215
  }
3277
3216
  var REACT_REFRESH_HEADER = `
@@ -3370,8 +3309,11 @@ async function getRouteMetadata(cache, ctx, viteChildCompiler, route, readRouteF
3370
3309
  };
3371
3310
  return info;
3372
3311
  }
3312
+ function isPrerenderingEnabled(reactRouterConfig) {
3313
+ return reactRouterConfig.prerender != null && reactRouterConfig.prerender !== false;
3314
+ }
3373
3315
  function isSpaModeEnabled(reactRouterConfig) {
3374
- return reactRouterConfig.ssr === false && (reactRouterConfig.prerender == null || reactRouterConfig.prerender === false || Array.isArray(reactRouterConfig.prerender) && reactRouterConfig.prerender.length === 1 && reactRouterConfig.prerender[0] === "/");
3316
+ return reactRouterConfig.ssr === false && !isPrerenderingEnabled(reactRouterConfig);
3375
3317
  }
3376
3318
  async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, serverBuildFile) {
3377
3319
  let serverBuildPath = path6.join(serverBuildDirectory, serverBuildFile);
@@ -3383,20 +3325,44 @@ async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, ser
3383
3325
  };
3384
3326
  }
3385
3327
  async function handleSpaMode(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildFile, clientBuildDirectory) {
3386
- let { handler } = await getPrerenderBuildAndHandler(
3328
+ let { build, handler } = await getPrerenderBuildAndHandler(
3387
3329
  viteConfig,
3388
3330
  serverBuildDirectory,
3389
3331
  serverBuildFile
3390
3332
  );
3391
- let request = new Request(`http://localhost${reactRouterConfig.basename}`);
3333
+ let request = new Request(`http://localhost${reactRouterConfig.basename}`, {
3334
+ headers: {
3335
+ // Enable SPA mode in the server runtime and only render down to the root
3336
+ "X-React-Router-SPA-Mode": "yes"
3337
+ }
3338
+ });
3392
3339
  let response = await handler(request);
3393
3340
  let html = await response.text();
3394
- validatePrerenderedResponse(response, html, "SPA Mode", "/");
3395
- validatePrerenderedHtml(html, "SPA Mode");
3396
- await fse.writeFile(path6.join(clientBuildDirectory, "index.html"), html);
3397
- viteConfig.logger.info(
3398
- "SPA Mode: index.html has been written to your " + import_picocolors3.default.bold(path6.relative(process.cwd(), clientBuildDirectory)) + " directory"
3399
- );
3341
+ let isPrerenderSpaFallback = build.prerender.includes("/");
3342
+ let filename3 = isPrerenderSpaFallback ? "__spa-fallback__.html" : "index.html";
3343
+ if (response.status !== 200) {
3344
+ if (isPrerenderSpaFallback) {
3345
+ throw new Error(
3346
+ `Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
3347
+ ` + html
3348
+ );
3349
+ } else {
3350
+ throw new Error(
3351
+ `SPA Mode: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
3352
+ ` + html
3353
+ );
3354
+ }
3355
+ }
3356
+ if (!html.includes("window.__reactRouterContext =") || !html.includes("window.__reactRouterRouteModules =")) {
3357
+ throw new Error(
3358
+ "SPA Mode: Did you forget to include `<Scripts/>` in your root route? Your pre-rendered HTML cannot hydrate without `<Scripts />`."
3359
+ );
3360
+ }
3361
+ await fse.writeFile(path6.join(clientBuildDirectory, filename3), html);
3362
+ let prettyDir = path6.relative(process.cwd(), clientBuildDirectory);
3363
+ let prettyPath = path6.join(prettyDir, filename3);
3364
+ let prefix = isPrerenderSpaFallback ? "Prerender" : "SPA Mode";
3365
+ viteConfig.logger.info(`${prefix}: Generated \`${prettyPath}\``);
3400
3366
  }
3401
3367
  async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildPath, clientBuildDirectory) {
3402
3368
  let { build, handler } = await getPrerenderBuildAndHandler(
@@ -3405,29 +3371,22 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
3405
3371
  serverBuildPath
3406
3372
  );
3407
3373
  let routes = createPrerenderRoutes(build.routes);
3408
- let routesToPrerender;
3409
- if (typeof reactRouterConfig.prerender === "boolean") {
3410
- invariant(reactRouterConfig.prerender, "Expected prerender:true");
3411
- routesToPrerender = determineStaticPrerenderRoutes(
3412
- routes,
3413
- viteConfig,
3414
- true
3415
- );
3416
- } else if (typeof reactRouterConfig.prerender === "function") {
3417
- routesToPrerender = await reactRouterConfig.prerender({
3418
- getStaticPaths: () => determineStaticPrerenderRoutes(routes, viteConfig, false)
3419
- });
3420
- } else {
3421
- routesToPrerender = reactRouterConfig.prerender || ["/"];
3422
- }
3374
+ let prerenderedRoutes = /* @__PURE__ */ new Set();
3423
3375
  let headers = {
3424
3376
  // Header that can be used in the loader to know if you're running at
3425
3377
  // build time or runtime
3426
3378
  "X-React-Router-Prerender": "yes"
3427
3379
  };
3428
- for (let path7 of routesToPrerender) {
3380
+ for (let path7 of build.prerender) {
3429
3381
  let matches = (0, import_react_router2.matchRoutes)(routes, `/${path7}/`.replace(/^\/\/+/, "/"));
3430
- let hasLoaders = matches?.some((m) => m.route.loader);
3382
+ invariant(
3383
+ matches,
3384
+ `Unable to prerender path because it does not match any routes: ${path7}`
3385
+ );
3386
+ matches.forEach((m) => prerenderedRoutes.add(m.route.id));
3387
+ let hasLoaders = matches.some(
3388
+ (m) => build.assets.routes[m.route.id]?.hasLoader
3389
+ );
3431
3390
  let data;
3432
3391
  if (hasLoaders) {
3433
3392
  data = await prerenderData(
@@ -3467,8 +3426,34 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
3467
3426
  );
3468
3427
  }
3469
3428
  }
3429
+ if (reactRouterConfig.ssr === false) {
3430
+ let errors = [];
3431
+ for (let [routeId, route] of Object.entries(build.routes)) {
3432
+ let invalidApis = [];
3433
+ if (route) {
3434
+ if (route.module.headers) invalidApis.push("headers");
3435
+ if (route.module.action) invalidApis.push("action");
3436
+ if (invalidApis.length > 0) {
3437
+ errors.push(
3438
+ `Prerender: ${invalidApis.length} invalid route export(s) in \`${route.id}\` when prerendering with \`ssr:false\`: ${invalidApis.join(", ")}. See https://reactrouter.com/how-to/spa for more information.`
3439
+ );
3440
+ }
3441
+ if (route.module.loader && !prerenderedRoutes.has(routeId)) {
3442
+ errors.push(
3443
+ `Prerender: 1 invalid route export in \`${route.id}\` when using \`ssr:false\` with \`prerender\` because the route is never prerendered so the loader will never be called. See https://reactrouter.com/how-to/spa for more information.`
3444
+ );
3445
+ }
3446
+ }
3447
+ }
3448
+ if (errors.length > 0) {
3449
+ viteConfig.logger.error(errors.join("\n"));
3450
+ throw new Error(
3451
+ "Invalid route exports found when prerendering with `ssr:false`"
3452
+ );
3453
+ }
3454
+ }
3470
3455
  }
3471
- function determineStaticPrerenderRoutes(routes, viteConfig, isBooleanUsage = false) {
3456
+ function getStaticPrerenderPaths(routes) {
3472
3457
  let paths = ["/"];
3473
3458
  let paramRoutes = [];
3474
3459
  function recurse(subtree, prefix = "") {
@@ -3488,28 +3473,29 @@ function determineStaticPrerenderRoutes(routes, viteConfig, isBooleanUsage = fal
3488
3473
  }
3489
3474
  }
3490
3475
  recurse(routes);
3491
- if (isBooleanUsage && paramRoutes.length > 0) {
3492
- viteConfig.logger.warn(
3493
- [
3494
- "\u26A0\uFE0F Paths with dynamic/splat params cannot be prerendered when using `prerender: true`.",
3495
- "You may want to use the `prerender()` API to prerender the following paths:",
3496
- ...paramRoutes.map((p) => " - " + p)
3497
- ].join("\n")
3498
- );
3499
- }
3500
- return paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1"));
3476
+ return {
3477
+ paths: paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1")),
3478
+ paramRoutes
3479
+ };
3501
3480
  }
3502
3481
  async function prerenderData(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
3503
3482
  let normalizedPath = `${reactRouterConfig.basename}${prerenderPath === "/" ? "/_root.data" : `${prerenderPath.replace(/\/$/, "")}.data`}`.replace(/\/\/+/g, "/");
3504
3483
  let request = new Request(`http://localhost${normalizedPath}`, requestInit);
3505
3484
  let response = await handler(request);
3506
3485
  let data = await response.text();
3507
- validatePrerenderedResponse(response, data, "Prerender", normalizedPath);
3486
+ if (response.status !== 200) {
3487
+ throw new Error(
3488
+ `Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${path6}\` path.
3489
+ ${normalizedPath}`
3490
+ );
3491
+ }
3508
3492
  let outdir = path6.relative(process.cwd(), clientBuildDirectory);
3509
3493
  let outfile = path6.join(outdir, ...normalizedPath.split("/"));
3510
3494
  await fse.ensureDir(path6.dirname(outfile));
3511
3495
  await fse.outputFile(outfile, data);
3512
- viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
3496
+ viteConfig.logger.info(
3497
+ `Prerender Data: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
3498
+ );
3513
3499
  return data;
3514
3500
  }
3515
3501
  async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
@@ -3520,42 +3506,65 @@ async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reac
3520
3506
  let request = new Request(`http://localhost${normalizedPath}`, requestInit);
3521
3507
  let response = await handler(request);
3522
3508
  let html = await response.text();
3523
- validatePrerenderedResponse(response, html, "Prerender", normalizedPath);
3524
- if (!reactRouterConfig.ssr) {
3525
- validatePrerenderedHtml(html, "Prerender");
3509
+ if (response.status !== 200) {
3510
+ throw new Error(
3511
+ `Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
3512
+ ${html}`
3513
+ );
3526
3514
  }
3527
3515
  let outdir = path6.relative(process.cwd(), clientBuildDirectory);
3528
3516
  let outfile = path6.join(outdir, ...normalizedPath.split("/"), "index.html");
3529
3517
  await fse.ensureDir(path6.dirname(outfile));
3530
3518
  await fse.outputFile(outfile, html);
3531
- viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
3519
+ viteConfig.logger.info(
3520
+ `Prerender: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
3521
+ );
3532
3522
  }
3533
3523
  async function prerenderResourceRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
3534
3524
  let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(/\/\/+/g, "/").replace(/\/$/g, "");
3535
3525
  let request = new Request(`http://localhost${normalizedPath}`, requestInit);
3536
3526
  let response = await handler(request);
3537
3527
  let text = await response.text();
3538
- validatePrerenderedResponse(response, text, "Prerender", normalizedPath);
3539
- let outdir = path6.relative(process.cwd(), clientBuildDirectory);
3540
- let outfile = path6.join(outdir, ...normalizedPath.split("/"));
3541
- await fse.ensureDir(path6.dirname(outfile));
3542
- await fse.outputFile(outfile, text);
3543
- viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
3544
- }
3545
- function validatePrerenderedResponse(response, html, prefix, path7) {
3546
3528
  if (response.status !== 200) {
3547
3529
  throw new Error(
3548
- `${prefix}: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${path7}\` path.
3549
- ${html}`
3530
+ `Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
3531
+ ${text}`
3550
3532
  );
3551
3533
  }
3534
+ let outdir = path6.relative(process.cwd(), clientBuildDirectory);
3535
+ let outfile = path6.join(outdir, ...normalizedPath.split("/"));
3536
+ await fse.ensureDir(path6.dirname(outfile));
3537
+ await fse.outputFile(outfile, text);
3538
+ viteConfig.logger.info(
3539
+ `Prerender: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
3540
+ );
3552
3541
  }
3553
- function validatePrerenderedHtml(html, prefix) {
3554
- if (!html.includes("window.__reactRouterContext =") || !html.includes("window.__reactRouterRouteModules =")) {
3555
- throw new Error(
3556
- `${prefix}: Did you forget to include <Scripts/> in your root route? Your pre-rendered HTML files cannot hydrate without \`<Scripts />\`.`
3557
- );
3542
+ async function getPrerenderPaths(prerender, ssr, routes) {
3543
+ let prerenderPaths = [];
3544
+ if (prerender != null && prerender !== false) {
3545
+ let prerenderRoutes = createPrerenderRoutes(routes);
3546
+ if (prerender === true) {
3547
+ let { paths, paramRoutes } = getStaticPrerenderPaths(prerenderRoutes);
3548
+ if (!ssr && paramRoutes.length > 0) {
3549
+ console.warn(
3550
+ import_picocolors3.default.yellow(
3551
+ [
3552
+ "\u26A0\uFE0F Paths with dynamic/splat params cannot be prerendered when using `prerender: true`. You may want to use the `prerender()` API to prerender the following paths:",
3553
+ ...paramRoutes.map((p) => " - " + p)
3554
+ ].join("\n")
3555
+ )
3556
+ );
3557
+ }
3558
+ prerenderPaths = paths;
3559
+ } else if (typeof prerender === "function") {
3560
+ prerenderPaths = await prerender({
3561
+ getStaticPaths: () => getStaticPrerenderPaths(prerenderRoutes).paths
3562
+ });
3563
+ } else {
3564
+ prerenderPaths = prerender || ["/"];
3565
+ }
3558
3566
  }
3567
+ return prerenderPaths;
3559
3568
  }
3560
3569
  function groupRoutesByParentId2(manifest) {
3561
3570
  let routes = {};
@@ -3573,26 +3582,70 @@ function groupRoutesByParentId2(manifest) {
3573
3582
  function createPrerenderRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId2(manifest)) {
3574
3583
  return (routesByParentId[parentId] || []).map((route) => {
3575
3584
  let commonRoute = {
3576
- // Always include root due to default boundaries
3577
- hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
3578
3585
  id: route.id,
3579
- path: route.path,
3580
- loader: route.module.loader ? () => null : void 0,
3581
- action: void 0,
3582
- handle: route.module.handle
3583
- // middleware is not necessary here since we just need to know which
3584
- // routes have loaders so we know what paths to prerender
3586
+ path: route.path
3585
3587
  };
3586
- return route.index ? {
3587
- index: true,
3588
- ...commonRoute
3589
- } : {
3590
- caseSensitive: route.caseSensitive,
3588
+ if (route.index) {
3589
+ return {
3590
+ index: true,
3591
+ ...commonRoute
3592
+ };
3593
+ }
3594
+ return {
3591
3595
  children: createPrerenderRoutes(manifest, route.id, routesByParentId),
3592
3596
  ...commonRoute
3593
3597
  };
3594
3598
  });
3595
3599
  }
3600
+ function getAddressableRoutes(routes) {
3601
+ let nonAddressableIds = /* @__PURE__ */ new Set();
3602
+ for (let id in routes) {
3603
+ let route = routes[id];
3604
+ if (route.index) {
3605
+ invariant(
3606
+ route.parentId,
3607
+ `Expected index route "${route.id}" to have "parentId" set`
3608
+ );
3609
+ nonAddressableIds.add(route.parentId);
3610
+ }
3611
+ if (typeof route.path !== "string" && !route.index) {
3612
+ nonAddressableIds.add(id);
3613
+ }
3614
+ }
3615
+ return Object.values(routes).filter(
3616
+ (route) => !nonAddressableIds.has(route.id)
3617
+ );
3618
+ }
3619
+ function getRouteBranch(routes, routeId) {
3620
+ let branch = [];
3621
+ let currentRouteId = routeId;
3622
+ while (currentRouteId) {
3623
+ let route = routes[currentRouteId];
3624
+ invariant(route, `Missing route for ${currentRouteId}`);
3625
+ branch.push(route);
3626
+ currentRouteId = route.parentId;
3627
+ }
3628
+ return branch.reverse();
3629
+ }
3630
+ function hasServerBundles(buildManifest) {
3631
+ return Object.keys(buildManifest.serverBundles ?? {}).length > 0;
3632
+ }
3633
+ function getRoutesByServerBundleId(buildManifest) {
3634
+ if (!buildManifest.routeIdToServerBundleId) {
3635
+ return {};
3636
+ }
3637
+ let routesByServerBundleId = {};
3638
+ for (let [routeId, serverBundleId] of Object.entries(
3639
+ buildManifest.routeIdToServerBundleId
3640
+ )) {
3641
+ routesByServerBundleId[serverBundleId] ??= {};
3642
+ let branch = getRouteBranch(buildManifest.routes, routeId);
3643
+ for (let route of branch) {
3644
+ routesByServerBundleId[serverBundleId][route.id] = route;
3645
+ }
3646
+ }
3647
+ return routesByServerBundleId;
3648
+ }
3596
3649
  var resolveRouteFileCode = async (ctx, input) => {
3597
3650
  if (typeof input === "string") return input;
3598
3651
  invariant(input.viteChildCompiler);
@@ -3657,6 +3710,192 @@ function validateRouteChunks({
3657
3710
  ].join("\n\n")
3658
3711
  );
3659
3712
  }
3713
+ async function getBuildManifest(ctx) {
3714
+ let { routes, serverBundles, appDirectory } = ctx.reactRouterConfig;
3715
+ if (!serverBundles) {
3716
+ return { routes };
3717
+ }
3718
+ let { normalizePath } = await import("vite");
3719
+ let serverBuildDirectory = getServerBuildDirectory(ctx);
3720
+ let resolvedAppDirectory = path6.resolve(ctx.rootDirectory, appDirectory);
3721
+ let rootRelativeRoutes = Object.fromEntries(
3722
+ Object.entries(routes).map(([id, route]) => {
3723
+ let filePath = path6.join(resolvedAppDirectory, route.file);
3724
+ let rootRelativeFilePath = normalizePath(
3725
+ path6.relative(ctx.rootDirectory, filePath)
3726
+ );
3727
+ return [id, { ...route, file: rootRelativeFilePath }];
3728
+ })
3729
+ );
3730
+ let buildManifest = {
3731
+ serverBundles: {},
3732
+ routeIdToServerBundleId: {},
3733
+ routes: rootRelativeRoutes
3734
+ };
3735
+ await Promise.all(
3736
+ getAddressableRoutes(routes).map(async (route) => {
3737
+ let branch = getRouteBranch(routes, route.id);
3738
+ let serverBundleId = await serverBundles({
3739
+ branch: branch.map(
3740
+ (route2) => configRouteToBranchRoute({
3741
+ ...route2,
3742
+ // Ensure absolute paths are passed to the serverBundles function
3743
+ file: path6.join(resolvedAppDirectory, route2.file)
3744
+ })
3745
+ )
3746
+ });
3747
+ if (typeof serverBundleId !== "string") {
3748
+ throw new Error(`The "serverBundles" function must return a string`);
3749
+ }
3750
+ if (!/^[a-zA-Z0-9-_]+$/.test(serverBundleId)) {
3751
+ throw new Error(
3752
+ `The "serverBundles" function must only return strings containing alphanumeric characters, hyphens and underscores.`
3753
+ );
3754
+ }
3755
+ buildManifest.routeIdToServerBundleId[route.id] = serverBundleId;
3756
+ buildManifest.serverBundles[serverBundleId] ??= {
3757
+ id: serverBundleId,
3758
+ file: normalizePath(
3759
+ path6.join(
3760
+ path6.relative(
3761
+ ctx.rootDirectory,
3762
+ path6.join(serverBuildDirectory, serverBundleId)
3763
+ ),
3764
+ ctx.reactRouterConfig.serverBuildFile
3765
+ )
3766
+ )
3767
+ };
3768
+ })
3769
+ );
3770
+ return buildManifest;
3771
+ }
3772
+ function mergeBuildOptions(base, overrides) {
3773
+ let vite2 = getVite();
3774
+ return vite2.mergeConfig({ build: base }, { build: overrides }).build;
3775
+ }
3776
+ async function getEnvironmentOptionsResolvers(ctx, buildManifest) {
3777
+ let { serverBuildFile, serverModuleFormat } = ctx.reactRouterConfig;
3778
+ function getBaseBuildOptions({
3779
+ viteUserConfig
3780
+ }) {
3781
+ return {
3782
+ cssMinify: viteUserConfig.build?.cssMinify ?? true,
3783
+ manifest: true,
3784
+ // The manifest is enabled for all builds to detect SSR-only assets
3785
+ rollupOptions: {
3786
+ preserveEntrySignatures: "exports-only",
3787
+ // Silence Rollup "use client" warnings
3788
+ // Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
3789
+ onwarn(warning, defaultHandler) {
3790
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
3791
+ return;
3792
+ }
3793
+ let userHandler = viteUserConfig.build?.rollupOptions?.onwarn;
3794
+ if (userHandler) {
3795
+ userHandler(warning, defaultHandler);
3796
+ } else {
3797
+ defaultHandler(warning);
3798
+ }
3799
+ }
3800
+ }
3801
+ };
3802
+ }
3803
+ function getBaseServerBuildOptions({
3804
+ viteUserConfig
3805
+ }) {
3806
+ return mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
3807
+ // We move SSR-only assets to client assets. Note that the
3808
+ // SSR build can also emit code-split JS files (e.g. by
3809
+ // dynamic import) under the same assets directory
3810
+ // regardless of "ssrEmitAssets" option, so we also need to
3811
+ // keep these JS files have to be kept as-is.
3812
+ ssrEmitAssets: true,
3813
+ copyPublicDir: false,
3814
+ // Assets in the public directory are only used by the client
3815
+ rollupOptions: {
3816
+ output: {
3817
+ entryFileNames: serverBuildFile,
3818
+ format: serverModuleFormat
3819
+ }
3820
+ }
3821
+ });
3822
+ }
3823
+ let environmentOptionsResolvers = {
3824
+ client: ({ viteUserConfig }) => ({
3825
+ build: mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
3826
+ rollupOptions: {
3827
+ input: [
3828
+ ctx.entryClientFilePath,
3829
+ ...Object.values(ctx.reactRouterConfig.routes).flatMap((route) => {
3830
+ let routeFilePath = path6.resolve(
3831
+ ctx.reactRouterConfig.appDirectory,
3832
+ route.file
3833
+ );
3834
+ let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
3835
+ let code = fse.readFileSync(routeFilePath, "utf-8");
3836
+ return [
3837
+ `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
3838
+ ...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
3839
+ (exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
3840
+ ) : []
3841
+ ].filter(isNonNullable);
3842
+ })
3843
+ ],
3844
+ output: {
3845
+ entryFileNames({ moduleIds }) {
3846
+ let routeChunkModuleId = moduleIds.find(isRouteChunkModuleId);
3847
+ let routeChunkName = routeChunkModuleId ? getRouteChunkNameFromModuleId(routeChunkModuleId) : null;
3848
+ let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
3849
+ return `assets/[name]${routeChunkSuffix}-[hash].js`;
3850
+ }
3851
+ }
3852
+ },
3853
+ outDir: getClientBuildDirectory(ctx.reactRouterConfig)
3854
+ })
3855
+ })
3856
+ };
3857
+ if (hasServerBundles(buildManifest)) {
3858
+ for (let [serverBundleId, routes] of Object.entries(
3859
+ getRoutesByServerBundleId(buildManifest)
3860
+ )) {
3861
+ environmentOptionsResolvers[`ssr-bundle-${serverBundleId}`] = ({
3862
+ viteUserConfig
3863
+ }) => ({
3864
+ build: mergeBuildOptions(
3865
+ getBaseServerBuildOptions({ viteUserConfig }),
3866
+ {
3867
+ outDir: getServerBuildDirectory(ctx, { serverBundleId }),
3868
+ rollupOptions: {
3869
+ input: `${virtual.serverBuild.id}?route-ids=${Object.keys(
3870
+ routes
3871
+ ).join(",")}`
3872
+ }
3873
+ }
3874
+ )
3875
+ });
3876
+ }
3877
+ } else {
3878
+ environmentOptionsResolvers.ssr = ({ viteUserConfig }) => ({
3879
+ build: mergeBuildOptions(getBaseServerBuildOptions({ viteUserConfig }), {
3880
+ outDir: getServerBuildDirectory(ctx),
3881
+ rollupOptions: {
3882
+ input: viteUserConfig.build?.rollupOptions?.input ?? virtual.serverBuild.id
3883
+ }
3884
+ })
3885
+ });
3886
+ }
3887
+ return environmentOptionsResolvers;
3888
+ }
3889
+ async function getEnvironmentOptions(ctx, environmentName, resolverOptions) {
3890
+ let buildManifest = await getBuildManifest(ctx);
3891
+ let environmentResolvers = await getEnvironmentOptionsResolvers(
3892
+ ctx,
3893
+ buildManifest
3894
+ );
3895
+ let resolver = environmentResolvers[environmentName];
3896
+ invariant(resolver, `Missing environment resolver for ${environmentName}`);
3897
+ return resolver(resolverOptions);
3898
+ }
3660
3899
  function isNonNullable(x) {
3661
3900
  return x != null;
3662
3901
  }