@react-router/dev 0.0.0-experimental-902325fda → 0.0.0-experimental-004e483a8

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-902325fda
2
+ * @react-router/dev v0.0.0-experimental-004e483a8
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -59,6 +59,7 @@ var import_kebabCase = __toESM(require("lodash/kebabCase"));
59
59
 
60
60
  // typegen/index.ts
61
61
  var import_node_fs2 = __toESM(require("fs"));
62
+ var import_dedent2 = __toESM(require("dedent"));
62
63
  var Path4 = __toESM(require("pathe"));
63
64
  var import_picocolors2 = __toESM(require("picocolors"));
64
65
 
@@ -453,7 +454,8 @@ async function resolveConfig({
453
454
  }
454
455
  let future = {
455
456
  unstable_optimizeDeps: reactRouterUserConfig.future?.unstable_optimizeDeps ?? false,
456
- unstable_splitRouteModules: reactRouterUserConfig.future?.unstable_splitRouteModules ?? false
457
+ unstable_splitRouteModules: reactRouterUserConfig.future?.unstable_splitRouteModules ?? false,
458
+ unstable_viteEnvironmentApi: reactRouterUserConfig.future?.unstable_viteEnvironmentApi ?? false
457
459
  };
458
460
  let reactRouterConfig = deepFreeze({
459
461
  appDirectory,
@@ -632,6 +634,19 @@ function findEntry(dir, basename2, options) {
632
634
  return void 0;
633
635
  }
634
636
 
637
+ // vite/babel.ts
638
+ var babel_exports = {};
639
+ __export(babel_exports, {
640
+ generate: () => generate,
641
+ parse: () => import_parser.parse,
642
+ t: () => t,
643
+ traverse: () => traverse
644
+ });
645
+ var import_parser = require("@babel/parser");
646
+ var t = __toESM(require("@babel/types"));
647
+ var traverse = require("@babel/traverse").default;
648
+ var generate = require("@babel/generator").default;
649
+
635
650
  // typegen/generate.ts
636
651
  var import_dedent = __toESM(require("dedent"));
637
652
  var Path3 = __toESM(require("pathe"));
@@ -653,7 +668,7 @@ function getTypesPath(ctx, route) {
653
668
  }
654
669
 
655
670
  // typegen/generate.ts
656
- function generate(ctx, route) {
671
+ function generate2(ctx, route) {
657
672
  const lineage = getRouteLineage(ctx.config.routes, route);
658
673
  const urlpath = lineage.map((route2) => route2.path).join("/");
659
674
  const typesPath = getTypesPath(ctx, route);
@@ -799,17 +814,77 @@ async function writeAll(ctx) {
799
814
  import_node_fs2.default.rmSync(typegenDir, { recursive: true, force: true });
800
815
  Object.values(ctx.config.routes).forEach((route) => {
801
816
  const typesPath = getTypesPath(ctx, route);
802
- const content = generate(ctx, route);
817
+ const content = generate2(ctx, route);
803
818
  import_node_fs2.default.mkdirSync(Path4.dirname(typesPath), { recursive: true });
804
819
  import_node_fs2.default.writeFileSync(typesPath, content);
805
820
  });
821
+ const registerPath = Path4.join(typegenDir, "+register.ts");
822
+ import_node_fs2.default.writeFileSync(registerPath, register(ctx));
806
823
  }
824
+ function register(ctx) {
825
+ const register2 = import_dedent2.default`
826
+ import "react-router";
807
827
 
808
- // vite/babel.ts
809
- var import_parser = require("@babel/parser");
810
- var t = __toESM(require("@babel/types"));
811
- var traverse = require("@babel/traverse").default;
812
- var generate2 = require("@babel/generator").default;
828
+ declare module "react-router" {
829
+ interface Register {
830
+ params: Params;
831
+ }
832
+ }
833
+ `;
834
+ const { t: t2 } = babel_exports;
835
+ const typeParams = t2.tsTypeAliasDeclaration(
836
+ t2.identifier("Params"),
837
+ null,
838
+ t2.tsTypeLiteral(
839
+ Object.values(ctx.config.routes).map((route) => {
840
+ const lineage = getRouteLineage2(ctx.config.routes, route);
841
+ const fullpath = lineage.map((route2) => route2.path).join("/");
842
+ const params = parseParams2(fullpath);
843
+ return t2.tsPropertySignature(
844
+ t2.stringLiteral(fullpath),
845
+ t2.tsTypeAnnotation(
846
+ t2.tsTypeLiteral(
847
+ Object.entries(params).map(([param, isRequired]) => {
848
+ const property = t2.tsPropertySignature(
849
+ t2.stringLiteral(param),
850
+ t2.tsTypeAnnotation(t2.tsStringKeyword())
851
+ );
852
+ property.optional = !isRequired;
853
+ return property;
854
+ })
855
+ )
856
+ )
857
+ );
858
+ })
859
+ )
860
+ );
861
+ return [register2, generate(typeParams).code].join("\n\n");
862
+ }
863
+ function parseParams2(fullpath) {
864
+ const result = {};
865
+ let segments = fullpath.split("/");
866
+ segments.forEach((segment) => {
867
+ const match = segment.match(/^:([\w-]+)(\?)?/);
868
+ if (!match) return;
869
+ const param = match[1];
870
+ const isRequired = match[2] === void 0;
871
+ result[param] ||= isRequired;
872
+ return;
873
+ });
874
+ const hasSplat = segments.at(-1) === "*";
875
+ if (hasSplat) result["*"] = true;
876
+ return result;
877
+ }
878
+ function getRouteLineage2(routes, route) {
879
+ const result = [];
880
+ while (route) {
881
+ result.push(route);
882
+ if (!route.parentId) break;
883
+ route = routes[route.parentId];
884
+ }
885
+ result.reverse();
886
+ return result;
887
+ }
813
888
 
814
889
  // vite/node-adapter.ts
815
890
  var import_node_events = require("events");
@@ -1597,7 +1672,7 @@ function getChunkedExport(code, exportName, generateOptions = {}, cache, cacheKe
1597
1672
  }
1598
1673
  throw new Error(`Unknown export node type: ${node.type}`);
1599
1674
  }).filter((node) => node !== null);
1600
- return generate2(ast, generateOptions);
1675
+ return generate(ast, generateOptions);
1601
1676
  }
1602
1677
  );
1603
1678
  }
@@ -1713,7 +1788,7 @@ function omitChunkedExports(code, exportNames, generateOptions = {}, cache, cach
1713
1788
  if (ast.program.body.length === 0) {
1714
1789
  return void 0;
1715
1790
  }
1716
- return generate2(ast, generateOptions);
1791
+ return generate(ast, generateOptions);
1717
1792
  }
1718
1793
  );
1719
1794
  }
@@ -1775,7 +1850,7 @@ function getRouteChunkNameFromModuleId(id) {
1775
1850
  }
1776
1851
 
1777
1852
  // vite/with-props.ts
1778
- var import_dedent2 = __toESM(require("dedent"));
1853
+ var import_dedent3 = __toESM(require("dedent"));
1779
1854
  var vmod = create("with-props");
1780
1855
  var NAMED_COMPONENT_EXPORTS = ["HydrateFallback", "ErrorBoundary"];
1781
1856
  var plugin = {
@@ -1786,7 +1861,7 @@ var plugin = {
1786
1861
  },
1787
1862
  async load(id) {
1788
1863
  if (id !== vmod.resolvedId) return;
1789
- return import_dedent2.default`
1864
+ return import_dedent3.default`
1790
1865
  import { createElement as h } from "react";
1791
1866
  import { useActionData, useLoaderData, useMatches, useParams, useRouteError } from "react-router";
1792
1867
 
@@ -1806,8 +1881,6 @@ var plugin = {
1806
1881
  return function Wrapped() {
1807
1882
  const props = {
1808
1883
  params: useParams(),
1809
- loaderData: useLoaderData(),
1810
- actionData: useActionData(),
1811
1884
  };
1812
1885
  return h(HydrateFallback, props);
1813
1886
  };
@@ -1915,6 +1988,20 @@ var CLIENT_ROUTE_EXPORTS = [
1915
1988
  "shouldRevalidate"
1916
1989
  ];
1917
1990
  var BUILD_CLIENT_ROUTE_QUERY_STRING = "?__react-router-build-client-route";
1991
+ var SSR_BUNDLE_PREFIX = "ssrBundle_";
1992
+ function isSeverBundleEnvironmentName(name) {
1993
+ return name.startsWith(SSR_BUNDLE_PREFIX);
1994
+ }
1995
+ function getServerEnvironmentEntries(record, buildManifest) {
1996
+ return Object.entries(record).filter(
1997
+ ([name]) => buildManifest.serverBundles ? isSeverBundleEnvironmentName(name) : name === "ssr"
1998
+ );
1999
+ }
2000
+ function getServerEnvironmentValues(record, buildManifest) {
2001
+ return getServerEnvironmentEntries(record, buildManifest).map(
2002
+ ([, value]) => value
2003
+ );
2004
+ }
1918
2005
  var isRouteEntryModuleId = (id) => {
1919
2006
  return id.endsWith(BUILD_CLIENT_ROUTE_QUERY_STRING);
1920
2007
  };
@@ -2083,7 +2170,7 @@ var resolveEnvironmentBuildContext = ({
2083
2170
  let buildContext = viteUserConfig.__reactRouterEnvironmentBuildContext;
2084
2171
  let resolvedBuildContext = {
2085
2172
  name: buildContext.name,
2086
- options: buildContext.resolveOptions({ viteCommand, viteUserConfig })
2173
+ options: buildContext.resolveOptions({ viteUserConfig })
2087
2174
  };
2088
2175
  return resolvedBuildContext;
2089
2176
  };
@@ -2108,6 +2195,7 @@ var reactRouterVitePlugin = () => {
2108
2195
  let viteUserConfig;
2109
2196
  let viteConfigEnv;
2110
2197
  let viteConfig;
2198
+ let buildManifest;
2111
2199
  let cssModulesManifest = {};
2112
2200
  let viteChildCompiler = null;
2113
2201
  let cache = /* @__PURE__ */ new Map();
@@ -2168,11 +2256,6 @@ var reactRouterVitePlugin = () => {
2168
2256
  // Otherwise, all routes are imported as usual
2169
2257
  ctx.reactRouterConfig.routes
2170
2258
  );
2171
- let prerenderPaths = await getPrerenderPaths(
2172
- ctx.reactRouterConfig.prerender,
2173
- ctx.reactRouterConfig.ssr,
2174
- routes
2175
- );
2176
2259
  return `
2177
2260
  import * as entryServer from ${JSON.stringify(
2178
2261
  resolveFileUrl(ctx, ctx.entryServerFilePath)
@@ -2199,7 +2282,6 @@ var reactRouterVitePlugin = () => {
2199
2282
  export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
2200
2283
  export const ssr = ${ctx.reactRouterConfig.ssr};
2201
2284
  export const isSpaMode = ${isSpaModeEnabled(ctx.reactRouterConfig)};
2202
- export const prerender = ${JSON.stringify(prerenderPaths)};
2203
2285
  export const publicPath = ${JSON.stringify(ctx.publicPath)};
2204
2286
  export const entry = { module: entryServer };
2205
2287
  export const routes = {
@@ -2432,14 +2514,6 @@ var reactRouterVitePlugin = () => {
2432
2514
  let viteClientConditions = [
2433
2515
  ...vite2.defaultClientConditions ?? []
2434
2516
  ];
2435
- let packageRoot = path6.dirname(
2436
- require.resolve("@react-router/dev/package.json")
2437
- );
2438
- let { moduleSyncEnabled } = await import(`file:///${path6.join(packageRoot, "module-sync-enabled/index.mjs")}`);
2439
- let viteServerConditions = [
2440
- ...vite2.defaultServerConditions ?? [],
2441
- ...moduleSyncEnabled ? ["module-sync"] : []
2442
- ];
2443
2517
  logger = vite2.createLogger(viteUserConfig.logLevel, {
2444
2518
  prefix: "[react-router]"
2445
2519
  });
@@ -2455,26 +2529,37 @@ var reactRouterVitePlugin = () => {
2455
2529
  watch: viteCommand === "serve"
2456
2530
  });
2457
2531
  await updatePluginContext();
2532
+ buildManifest = await getBuildManifest(ctx);
2458
2533
  Object.assign(
2459
2534
  process.env,
2460
2535
  vite2.loadEnv(
2461
2536
  viteConfigEnv.mode,
2462
- ctx.rootDirectory,
2537
+ viteUserConfig.envDir ?? ctx.rootDirectory,
2463
2538
  // We override default prefix of "VITE_" with a blank string since
2464
2539
  // we're targeting the server, so we want to load all environment
2465
2540
  // variables, not just those explicitly marked for the client
2466
2541
  ""
2467
2542
  )
2468
2543
  );
2544
+ let environments = await getEnvironmentsOptions(
2545
+ ctx,
2546
+ buildManifest,
2547
+ viteCommand,
2548
+ { viteUserConfig }
2549
+ );
2550
+ let serverEnvironment = getServerEnvironmentValues(
2551
+ environments,
2552
+ buildManifest
2553
+ )[0];
2554
+ invariant(serverEnvironment);
2555
+ let clientEnvironment = environments.client;
2556
+ invariant(clientEnvironment);
2469
2557
  return {
2470
2558
  __reactRouterPluginContext: ctx,
2471
2559
  appType: viteCommand === "serve" && viteConfigEnv.mode === "production" && ctx.reactRouterConfig.ssr === false ? "spa" : "custom",
2472
2560
  ssr: {
2473
- external: ssrExternals,
2474
- resolve: {
2475
- conditions: viteCommand === "build" ? viteServerConditions : ["development", ...viteServerConditions],
2476
- externalConditions: viteCommand === "build" ? viteServerConditions : ["development", ...viteServerConditions]
2477
- }
2561
+ external: serverEnvironment.resolve?.external,
2562
+ resolve: serverEnvironment.resolve
2478
2563
  },
2479
2564
  optimizeDeps: {
2480
2565
  entries: ctx.reactRouterConfig.future.unstable_optimizeDeps ? [
@@ -2523,11 +2608,41 @@ var reactRouterVitePlugin = () => {
2523
2608
  // will throw an error that the file is not allowed to be read.
2524
2609
  // https://vitejs.dev/config/server-options#server-fs-allow
2525
2610
  server: viteUserConfig.server?.fs?.allow ? { fs: { allow: defaultEntries } } : void 0,
2526
- build: ctx.environmentBuildContext?.options.build ?? (await getEnvironmentOptions(
2527
- ctx,
2528
- viteConfigEnv.isSsrBuild ? "ssr" : "client",
2529
- { viteCommand, viteUserConfig }
2530
- )).build
2611
+ ...ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? {
2612
+ environments,
2613
+ build: {
2614
+ // This isn't honored by the SSR environment config (which seems
2615
+ // to be a Vite bug?) so we set it here too.
2616
+ ssrEmitAssets: true
2617
+ },
2618
+ builder: {
2619
+ sharedConfigBuild: true,
2620
+ sharedPlugins: true,
2621
+ async buildApp(builder) {
2622
+ invariant(viteConfig);
2623
+ invariant(buildManifest);
2624
+ viteConfig.logger.info(
2625
+ "Using Vite Environment API (experimental)"
2626
+ );
2627
+ let { reactRouterConfig } = ctx;
2628
+ await cleanBuildDirectory(viteConfig, ctx);
2629
+ await builder.build(builder.environments.client);
2630
+ let serverEnvironments = getServerEnvironmentValues(
2631
+ builder.environments,
2632
+ buildManifest
2633
+ );
2634
+ await Promise.all(serverEnvironments.map(builder.build));
2635
+ await cleanViteManifests(environments, ctx);
2636
+ await reactRouterConfig.buildEnd?.({
2637
+ buildManifest,
2638
+ reactRouterConfig,
2639
+ viteConfig
2640
+ });
2641
+ }
2642
+ }
2643
+ } : {
2644
+ build: ctx.environmentBuildContext?.options.build ?? (viteConfigEnv.isSsrBuild ? serverEnvironment.build : clientEnvironment.build)
2645
+ }
2531
2646
  };
2532
2647
  },
2533
2648
  async configResolved(resolvedViteConfig) {
@@ -2685,14 +2800,15 @@ var reactRouterVitePlugin = () => {
2685
2800
  // After the SSR build is finished, we inspect the Vite manifest for
2686
2801
  // the SSR build and move server-only assets to client assets directory
2687
2802
  async handler() {
2688
- if (!viteConfigEnv.isSsrBuild) {
2803
+ let { future } = ctx.reactRouterConfig;
2804
+ if (future.unstable_viteEnvironmentApi ? this.environment.name === "client" : !viteConfigEnv.isSsrBuild) {
2689
2805
  return;
2690
2806
  }
2691
2807
  invariant(viteConfig);
2692
2808
  let clientBuildDirectory = getClientBuildDirectory(
2693
2809
  ctx.reactRouterConfig
2694
2810
  );
2695
- let serverBuildDirectory = ctx.environmentBuildContext?.options.build.outDir ?? getServerBuildDirectory(ctx);
2811
+ let serverBuildDirectory = future.unstable_viteEnvironmentApi ? this.environment.config?.build?.outDir : ctx.environmentBuildContext?.options.build?.outDir ?? getServerBuildDirectory(ctx);
2696
2812
  let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
2697
2813
  let ssrAssetPaths = getViteManifestAssetPaths(ssrViteManifest);
2698
2814
  let movedAssetPaths = [];
@@ -2726,7 +2842,7 @@ var reactRouterVitePlugin = () => {
2726
2842
  ].join("\n")
2727
2843
  );
2728
2844
  }
2729
- if (isPrerenderingEnabled(ctx.reactRouterConfig)) {
2845
+ if (ctx.reactRouterConfig.prerender != null && ctx.reactRouterConfig.prerender !== false) {
2730
2846
  await handlePrerender(
2731
2847
  viteConfig,
2732
2848
  ctx.reactRouterConfig,
@@ -3000,15 +3116,12 @@ var reactRouterVitePlugin = () => {
3000
3116
  if (!route) return;
3001
3117
  if (!options?.ssr && isSpaModeEnabled(ctx.reactRouterConfig)) {
3002
3118
  let exportNames = getExportNames(code);
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
- });
3119
+ let serverOnlyExports = exportNames.filter(
3120
+ (exp) => SERVER_ONLY_ROUTE_EXPORTS.includes(exp)
3121
+ );
3009
3122
  if (serverOnlyExports.length > 0) {
3010
3123
  let str = serverOnlyExports.map((e) => `\`${e}\``).join(", ");
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.`;
3124
+ let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://remix.run/guides/spa-mode for more information.`;
3012
3125
  throw Error(message);
3013
3126
  }
3014
3127
  if (route.id !== "root") {
@@ -3016,7 +3129,7 @@ var reactRouterVitePlugin = () => {
3016
3129
  (exp) => exp === "HydrateFallback"
3017
3130
  );
3018
3131
  if (hasHydrateFallback) {
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.`;
3132
+ 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.`;
3020
3133
  throw Error(message);
3021
3134
  }
3022
3135
  }
@@ -3027,7 +3140,7 @@ var reactRouterVitePlugin = () => {
3027
3140
  removeExports(ast, SERVER_ONLY_ROUTE_EXPORTS);
3028
3141
  }
3029
3142
  transform(ast);
3030
- return generate2(ast, {
3143
+ return generate(ast, {
3031
3144
  sourceMaps: true,
3032
3145
  filename: id,
3033
3146
  sourceFileName: filepath
@@ -3309,11 +3422,8 @@ async function getRouteMetadata(cache, ctx, viteChildCompiler, route, readRouteF
3309
3422
  };
3310
3423
  return info;
3311
3424
  }
3312
- function isPrerenderingEnabled(reactRouterConfig) {
3313
- return reactRouterConfig.prerender != null && reactRouterConfig.prerender !== false;
3314
- }
3315
3425
  function isSpaModeEnabled(reactRouterConfig) {
3316
- return reactRouterConfig.ssr === false && !isPrerenderingEnabled(reactRouterConfig);
3426
+ return reactRouterConfig.ssr === false && (reactRouterConfig.prerender == null || reactRouterConfig.prerender === false || Array.isArray(reactRouterConfig.prerender) && reactRouterConfig.prerender.length === 1 && reactRouterConfig.prerender[0] === "/");
3317
3427
  }
3318
3428
  async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, serverBuildFile) {
3319
3429
  let serverBuildPath = path6.join(serverBuildDirectory, serverBuildFile);
@@ -3325,49 +3435,20 @@ async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, ser
3325
3435
  };
3326
3436
  }
3327
3437
  async function handleSpaMode(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildFile, clientBuildDirectory) {
3328
- let { build, handler } = await getPrerenderBuildAndHandler(
3438
+ let { handler } = await getPrerenderBuildAndHandler(
3329
3439
  viteConfig,
3330
3440
  serverBuildDirectory,
3331
3441
  serverBuildFile
3332
3442
  );
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
- });
3443
+ let request = new Request(`http://localhost${reactRouterConfig.basename}`);
3339
3444
  let response = await handler(request);
3340
3445
  let html = await response.text();
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
- if (build.prerender.length > 0) {
3365
- viteConfig.logger.info(
3366
- `Prerender (html): SPA Fallback -> ${import_picocolors3.default.bold(prettyPath)}`
3367
- );
3368
- } else {
3369
- viteConfig.logger.info(`SPA Mode: Generated ${import_picocolors3.default.bold(prettyPath)}`);
3370
- }
3446
+ validatePrerenderedResponse(response, html, "SPA Mode", "/");
3447
+ validatePrerenderedHtml(html, "SPA Mode");
3448
+ await fse.writeFile(path6.join(clientBuildDirectory, "index.html"), html);
3449
+ viteConfig.logger.info(
3450
+ "SPA Mode: index.html has been written to your " + import_picocolors3.default.bold(path6.relative(process.cwd(), clientBuildDirectory)) + " directory"
3451
+ );
3371
3452
  }
3372
3453
  async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildPath, clientBuildDirectory) {
3373
3454
  let { build, handler } = await getPrerenderBuildAndHandler(
@@ -3376,22 +3457,29 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
3376
3457
  serverBuildPath
3377
3458
  );
3378
3459
  let routes = createPrerenderRoutes(build.routes);
3379
- let prerenderedRoutes = /* @__PURE__ */ new Set();
3460
+ let routesToPrerender;
3461
+ if (typeof reactRouterConfig.prerender === "boolean") {
3462
+ invariant(reactRouterConfig.prerender, "Expected prerender:true");
3463
+ routesToPrerender = determineStaticPrerenderRoutes(
3464
+ routes,
3465
+ viteConfig,
3466
+ true
3467
+ );
3468
+ } else if (typeof reactRouterConfig.prerender === "function") {
3469
+ routesToPrerender = await reactRouterConfig.prerender({
3470
+ getStaticPaths: () => determineStaticPrerenderRoutes(routes, viteConfig, false)
3471
+ });
3472
+ } else {
3473
+ routesToPrerender = reactRouterConfig.prerender || ["/"];
3474
+ }
3380
3475
  let headers = {
3381
3476
  // Header that can be used in the loader to know if you're running at
3382
3477
  // build time or runtime
3383
3478
  "X-React-Router-Prerender": "yes"
3384
3479
  };
3385
- for (let path7 of build.prerender) {
3480
+ for (let path7 of routesToPrerender) {
3386
3481
  let matches = (0, import_react_router2.matchRoutes)(routes, `/${path7}/`.replace(/^\/\/+/, "/"));
3387
- invariant(
3388
- matches,
3389
- `Unable to prerender path because it does not match any routes: ${path7}`
3390
- );
3391
- matches.forEach((m) => prerenderedRoutes.add(m.route.id));
3392
- let hasLoaders = matches.some(
3393
- (m) => build.assets.routes[m.route.id]?.hasLoader
3394
- );
3482
+ let hasLoaders = matches?.some((m) => m.route.loader);
3395
3483
  let data;
3396
3484
  if (hasLoaders) {
3397
3485
  data = await prerenderData(
@@ -3431,34 +3519,8 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
3431
3519
  );
3432
3520
  }
3433
3521
  }
3434
- if (reactRouterConfig.ssr === false) {
3435
- let errors = [];
3436
- for (let [routeId, route] of Object.entries(build.routes)) {
3437
- let invalidApis = [];
3438
- if (route) {
3439
- if (route.module.headers) invalidApis.push("headers");
3440
- if (route.module.action) invalidApis.push("action");
3441
- if (invalidApis.length > 0) {
3442
- errors.push(
3443
- `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.`
3444
- );
3445
- }
3446
- if (route.module.loader && !prerenderedRoutes.has(routeId)) {
3447
- errors.push(
3448
- `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.`
3449
- );
3450
- }
3451
- }
3452
- }
3453
- if (errors.length > 0) {
3454
- viteConfig.logger.error(errors.join("\n"));
3455
- throw new Error(
3456
- "Invalid route exports found when prerendering with `ssr:false`"
3457
- );
3458
- }
3459
- }
3460
3522
  }
3461
- function getStaticPrerenderPaths(routes) {
3523
+ function determineStaticPrerenderRoutes(routes, viteConfig, isBooleanUsage = false) {
3462
3524
  let paths = ["/"];
3463
3525
  let paramRoutes = [];
3464
3526
  function recurse(subtree, prefix = "") {
@@ -3478,29 +3540,28 @@ function getStaticPrerenderPaths(routes) {
3478
3540
  }
3479
3541
  }
3480
3542
  recurse(routes);
3481
- return {
3482
- paths: paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1")),
3483
- paramRoutes
3484
- };
3543
+ if (isBooleanUsage && paramRoutes.length > 0) {
3544
+ viteConfig.logger.warn(
3545
+ [
3546
+ "\u26A0\uFE0F Paths with dynamic/splat params cannot be prerendered when using `prerender: true`.",
3547
+ "You may want to use the `prerender()` API to prerender the following paths:",
3548
+ ...paramRoutes.map((p) => " - " + p)
3549
+ ].join("\n")
3550
+ );
3551
+ }
3552
+ return paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1"));
3485
3553
  }
3486
3554
  async function prerenderData(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
3487
3555
  let normalizedPath = `${reactRouterConfig.basename}${prerenderPath === "/" ? "/_root.data" : `${prerenderPath.replace(/\/$/, "")}.data`}`.replace(/\/\/+/g, "/");
3488
3556
  let request = new Request(`http://localhost${normalizedPath}`, requestInit);
3489
3557
  let response = await handler(request);
3490
3558
  let data = await response.text();
3491
- if (response.status !== 200) {
3492
- throw new Error(
3493
- `Prerender (data): Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${path6}\` path.
3494
- ${normalizedPath}`
3495
- );
3496
- }
3559
+ validatePrerenderedResponse(response, data, "Prerender", normalizedPath);
3497
3560
  let outdir = path6.relative(process.cwd(), clientBuildDirectory);
3498
3561
  let outfile = path6.join(outdir, ...normalizedPath.split("/"));
3499
3562
  await fse.ensureDir(path6.dirname(outfile));
3500
3563
  await fse.outputFile(outfile, data);
3501
- viteConfig.logger.info(
3502
- `Prerender (data): ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
3503
- );
3564
+ viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
3504
3565
  return data;
3505
3566
  }
3506
3567
  async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
@@ -3511,65 +3572,42 @@ async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reac
3511
3572
  let request = new Request(`http://localhost${normalizedPath}`, requestInit);
3512
3573
  let response = await handler(request);
3513
3574
  let html = await response.text();
3514
- if (response.status !== 200) {
3515
- throw new Error(
3516
- `Prerender (html): Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
3517
- ${html}`
3518
- );
3575
+ validatePrerenderedResponse(response, html, "Prerender", normalizedPath);
3576
+ if (!reactRouterConfig.ssr) {
3577
+ validatePrerenderedHtml(html, "Prerender");
3519
3578
  }
3520
3579
  let outdir = path6.relative(process.cwd(), clientBuildDirectory);
3521
3580
  let outfile = path6.join(outdir, ...normalizedPath.split("/"), "index.html");
3522
3581
  await fse.ensureDir(path6.dirname(outfile));
3523
3582
  await fse.outputFile(outfile, html);
3524
- viteConfig.logger.info(
3525
- `Prerender (html): ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
3526
- );
3583
+ viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
3527
3584
  }
3528
3585
  async function prerenderResourceRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
3529
3586
  let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(/\/\/+/g, "/").replace(/\/$/g, "");
3530
3587
  let request = new Request(`http://localhost${normalizedPath}`, requestInit);
3531
3588
  let response = await handler(request);
3532
3589
  let text = await response.text();
3533
- if (response.status !== 200) {
3534
- throw new Error(
3535
- `Prerender (resource): Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
3536
- ${text}`
3537
- );
3538
- }
3590
+ validatePrerenderedResponse(response, text, "Prerender", normalizedPath);
3539
3591
  let outdir = path6.relative(process.cwd(), clientBuildDirectory);
3540
3592
  let outfile = path6.join(outdir, ...normalizedPath.split("/"));
3541
3593
  await fse.ensureDir(path6.dirname(outfile));
3542
3594
  await fse.outputFile(outfile, text);
3543
- viteConfig.logger.info(
3544
- `Prerender (resource): ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
3545
- );
3595
+ viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
3546
3596
  }
3547
- async function getPrerenderPaths(prerender, ssr, routes) {
3548
- let prerenderPaths = [];
3549
- if (prerender != null && prerender !== false) {
3550
- let prerenderRoutes = createPrerenderRoutes(routes);
3551
- if (prerender === true) {
3552
- let { paths, paramRoutes } = getStaticPrerenderPaths(prerenderRoutes);
3553
- if (!ssr && paramRoutes.length > 0) {
3554
- console.warn(
3555
- import_picocolors3.default.yellow(
3556
- [
3557
- "\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:",
3558
- ...paramRoutes.map((p) => " - " + p)
3559
- ].join("\n")
3560
- )
3561
- );
3562
- }
3563
- prerenderPaths = paths;
3564
- } else if (typeof prerender === "function") {
3565
- prerenderPaths = await prerender({
3566
- getStaticPaths: () => getStaticPrerenderPaths(prerenderRoutes).paths
3567
- });
3568
- } else {
3569
- prerenderPaths = prerender || ["/"];
3570
- }
3597
+ function validatePrerenderedResponse(response, html, prefix, path7) {
3598
+ if (response.status !== 200) {
3599
+ throw new Error(
3600
+ `${prefix}: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${path7}\` path.
3601
+ ${html}`
3602
+ );
3603
+ }
3604
+ }
3605
+ function validatePrerenderedHtml(html, prefix) {
3606
+ if (!html.includes("window.__reactRouterContext =") || !html.includes("window.__reactRouterRouteModules =")) {
3607
+ throw new Error(
3608
+ `${prefix}: Did you forget to include <Scripts/> in your root route? Your pre-rendered HTML files cannot hydrate without \`<Scripts />\`.`
3609
+ );
3571
3610
  }
3572
- return prerenderPaths;
3573
3611
  }
3574
3612
  function groupRoutesByParentId2(manifest) {
3575
3613
  let routes = {};
@@ -3587,16 +3625,19 @@ function groupRoutesByParentId2(manifest) {
3587
3625
  function createPrerenderRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId2(manifest)) {
3588
3626
  return (routesByParentId[parentId] || []).map((route) => {
3589
3627
  let commonRoute = {
3628
+ // Always include root due to default boundaries
3629
+ hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
3590
3630
  id: route.id,
3591
- path: route.path
3631
+ path: route.path,
3632
+ loader: route.module.loader ? () => null : void 0,
3633
+ action: void 0,
3634
+ handle: route.module.handle
3592
3635
  };
3593
- if (route.index) {
3594
- return {
3595
- index: true,
3596
- ...commonRoute
3597
- };
3598
- }
3599
- return {
3636
+ return route.index ? {
3637
+ index: true,
3638
+ ...commonRoute
3639
+ } : {
3640
+ caseSensitive: route.caseSensitive,
3600
3641
  children: createPrerenderRoutes(manifest, route.id, routesByParentId),
3601
3642
  ...commonRoute
3602
3643
  };
@@ -3715,6 +3756,39 @@ function validateRouteChunks({
3715
3756
  ].join("\n\n")
3716
3757
  );
3717
3758
  }
3759
+ async function cleanBuildDirectory(viteConfig, ctx) {
3760
+ let buildDirectory = ctx.reactRouterConfig.buildDirectory;
3761
+ let isWithinRoot = () => {
3762
+ let relativePath = path6.relative(ctx.rootDirectory, buildDirectory);
3763
+ return !relativePath.startsWith("..") && !path6.isAbsolute(relativePath);
3764
+ };
3765
+ if (viteConfig.build.emptyOutDir ?? isWithinRoot()) {
3766
+ await fse.remove(buildDirectory);
3767
+ }
3768
+ }
3769
+ async function cleanViteManifests(environmentsOptions, ctx) {
3770
+ let viteManifestPaths = Object.entries(environmentsOptions).map(
3771
+ ([environmentName, options]) => {
3772
+ let outDir = options.build?.outDir;
3773
+ invariant(outDir, `Expected build.outDir for ${environmentName}`);
3774
+ return path6.join(outDir, ".vite/manifest.json");
3775
+ }
3776
+ );
3777
+ await Promise.all(
3778
+ viteManifestPaths.map(async (viteManifestPath) => {
3779
+ let manifestExists = await fse.pathExists(viteManifestPath);
3780
+ if (!manifestExists) return;
3781
+ if (!ctx.viteManifestEnabled) {
3782
+ await fse.remove(viteManifestPath);
3783
+ }
3784
+ let viteDir = path6.dirname(viteManifestPath);
3785
+ let viteDirFiles = await fse.readdir(viteDir);
3786
+ if (viteDirFiles.length === 0) {
3787
+ await fse.remove(viteDir);
3788
+ }
3789
+ })
3790
+ );
3791
+ }
3718
3792
  async function getBuildManifest(ctx) {
3719
3793
  let { routes, serverBundles, appDirectory } = ctx.reactRouterConfig;
3720
3794
  if (!serverBundles) {
@@ -3774,77 +3848,101 @@ async function getBuildManifest(ctx) {
3774
3848
  );
3775
3849
  return buildManifest;
3776
3850
  }
3777
- function mergeBuildOptions(base, overrides) {
3851
+ function mergeEnvironmentOptions(base, ...overrides) {
3778
3852
  let vite2 = getVite();
3779
- return vite2.mergeConfig({ build: base }, { build: overrides }).build;
3853
+ return overrides.reduce(
3854
+ (merged, override) => vite2.mergeConfig(merged, override, false),
3855
+ base
3856
+ );
3780
3857
  }
3781
- async function getEnvironmentOptionsResolvers(ctx, buildManifest) {
3858
+ async function getEnvironmentOptionsResolvers(ctx, buildManifest, viteCommand) {
3782
3859
  let { serverBuildFile, serverModuleFormat } = ctx.reactRouterConfig;
3783
- function getBaseBuildOptions({
3860
+ let packageRoot = path6.dirname(
3861
+ require.resolve("@react-router/dev/package.json")
3862
+ );
3863
+ let { moduleSyncEnabled } = await import(`file:///${path6.join(packageRoot, "module-sync-enabled/index.mjs")}`);
3864
+ let vite2 = getVite();
3865
+ let viteServerConditions = [
3866
+ ...vite2.defaultServerConditions ?? [],
3867
+ ...moduleSyncEnabled ? ["module-sync"] : []
3868
+ ];
3869
+ function getBaseOptions({
3784
3870
  viteUserConfig
3785
3871
  }) {
3786
3872
  return {
3787
- cssMinify: viteUserConfig.build?.cssMinify ?? true,
3788
- manifest: true,
3789
- // The manifest is enabled for all builds to detect SSR-only assets
3790
- rollupOptions: {
3791
- preserveEntrySignatures: "exports-only",
3792
- // Silence Rollup "use client" warnings
3793
- // Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
3794
- onwarn(warning, defaultHandler) {
3795
- if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
3796
- return;
3797
- }
3798
- let userHandler = viteUserConfig.build?.rollupOptions?.onwarn;
3799
- if (userHandler) {
3800
- userHandler(warning, defaultHandler);
3801
- } else {
3802
- defaultHandler(warning);
3873
+ build: {
3874
+ cssMinify: viteUserConfig.build?.cssMinify ?? true,
3875
+ manifest: true,
3876
+ // The manifest is enabled for all builds to detect SSR-only assets
3877
+ rollupOptions: {
3878
+ preserveEntrySignatures: "exports-only",
3879
+ // Silence Rollup "use client" warnings
3880
+ // Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
3881
+ onwarn(warning, defaultHandler) {
3882
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
3883
+ return;
3884
+ }
3885
+ let userHandler = viteUserConfig.build?.rollupOptions?.onwarn;
3886
+ if (userHandler) {
3887
+ userHandler(warning, defaultHandler);
3888
+ } else {
3889
+ defaultHandler(warning);
3890
+ }
3803
3891
  }
3804
3892
  }
3805
3893
  }
3806
3894
  };
3807
3895
  }
3808
- function getBaseServerBuildOptions({
3896
+ function getBaseServerOptions({
3809
3897
  viteUserConfig
3810
3898
  }) {
3811
- return mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
3812
- // We move SSR-only assets to client assets. Note that the
3813
- // SSR build can also emit code-split JS files (e.g. by
3814
- // dynamic import) under the same assets directory
3815
- // regardless of "ssrEmitAssets" option, so we also need to
3816
- // keep these JS files have to be kept as-is.
3817
- ssrEmitAssets: true,
3818
- copyPublicDir: false,
3819
- // Assets in the public directory are only used by the client
3820
- rollupOptions: {
3821
- output: {
3822
- entryFileNames: serverBuildFile,
3823
- format: serverModuleFormat
3899
+ let conditions = viteCommand === "build" ? viteServerConditions : ["development", ...viteServerConditions];
3900
+ return mergeEnvironmentOptions(getBaseOptions({ viteUserConfig }), {
3901
+ resolve: {
3902
+ external: ssrExternals,
3903
+ conditions,
3904
+ externalConditions: conditions
3905
+ },
3906
+ build: {
3907
+ // We move SSR-only assets to client assets. Note that the
3908
+ // SSR build can also emit code-split JS files (e.g. by
3909
+ // dynamic import) under the same assets directory
3910
+ // regardless of "ssrEmitAssets" option, so we also need to
3911
+ // keep these JS files have to be kept as-is.
3912
+ ssrEmitAssets: true,
3913
+ copyPublicDir: false,
3914
+ // Assets in the public directory are only used by the client
3915
+ rollupOptions: {
3916
+ output: {
3917
+ entryFileNames: serverBuildFile,
3918
+ format: serverModuleFormat
3919
+ }
3824
3920
  }
3825
3921
  }
3826
3922
  });
3827
3923
  }
3828
3924
  let environmentOptionsResolvers = {
3829
- client: ({ viteUserConfig }) => ({
3830
- build: mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
3925
+ client: ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseOptions({ viteUserConfig }), {
3926
+ build: {
3831
3927
  rollupOptions: {
3832
3928
  input: [
3833
3929
  ctx.entryClientFilePath,
3834
- ...Object.values(ctx.reactRouterConfig.routes).flatMap((route) => {
3835
- let routeFilePath = path6.resolve(
3836
- ctx.reactRouterConfig.appDirectory,
3837
- route.file
3838
- );
3839
- let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
3840
- let code = fse.readFileSync(routeFilePath, "utf-8");
3841
- return [
3842
- `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
3843
- ...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
3844
- (exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
3845
- ) : []
3846
- ].filter(isNonNullable);
3847
- })
3930
+ ...Object.values(ctx.reactRouterConfig.routes).flatMap(
3931
+ (route) => {
3932
+ let routeFilePath = path6.resolve(
3933
+ ctx.reactRouterConfig.appDirectory,
3934
+ route.file
3935
+ );
3936
+ let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
3937
+ let code = fse.readFileSync(routeFilePath, "utf-8");
3938
+ return [
3939
+ `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
3940
+ ...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
3941
+ (exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
3942
+ ) : []
3943
+ ].filter(isNonNullable);
3944
+ }
3945
+ )
3848
3946
  ],
3849
3947
  output: {
3850
3948
  entryFileNames({ moduleIds }) {
@@ -3856,19 +3954,19 @@ async function getEnvironmentOptionsResolvers(ctx, buildManifest) {
3856
3954
  }
3857
3955
  },
3858
3956
  outDir: getClientBuildDirectory(ctx.reactRouterConfig)
3859
- })
3957
+ }
3860
3958
  })
3861
3959
  };
3862
3960
  if (hasServerBundles(buildManifest)) {
3863
3961
  for (let [serverBundleId, routes] of Object.entries(
3864
3962
  getRoutesByServerBundleId(buildManifest)
3865
3963
  )) {
3866
- environmentOptionsResolvers[`ssr-bundle-${serverBundleId}`] = ({
3867
- viteUserConfig
3868
- }) => ({
3869
- build: mergeBuildOptions(
3870
- getBaseServerBuildOptions({ viteUserConfig }),
3871
- {
3964
+ const serverBundleEnvironmentId = serverBundleId.replaceAll("-", "_");
3965
+ const environmentName = `${SSR_BUNDLE_PREFIX}${serverBundleEnvironmentId}`;
3966
+ environmentOptionsResolvers[environmentName] = ({ viteUserConfig }) => mergeEnvironmentOptions(
3967
+ getBaseServerOptions({ viteUserConfig }),
3968
+ {
3969
+ build: {
3872
3970
  outDir: getServerBuildDirectory(ctx, { serverBundleId }),
3873
3971
  rollupOptions: {
3874
3972
  input: `${virtual.serverBuild.id}?route-ids=${Object.keys(
@@ -3876,30 +3974,43 @@ async function getEnvironmentOptionsResolvers(ctx, buildManifest) {
3876
3974
  ).join(",")}`
3877
3975
  }
3878
3976
  }
3879
- )
3880
- });
3977
+ },
3978
+ // Ensure server bundle environments extend the user's SSR
3979
+ // environment config if it exists
3980
+ viteUserConfig.environments?.ssr ?? {}
3981
+ );
3881
3982
  }
3882
3983
  } else {
3883
- environmentOptionsResolvers.ssr = ({ viteUserConfig }) => ({
3884
- build: mergeBuildOptions(getBaseServerBuildOptions({ viteUserConfig }), {
3984
+ environmentOptionsResolvers.ssr = ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseServerOptions({ viteUserConfig }), {
3985
+ build: {
3885
3986
  outDir: getServerBuildDirectory(ctx),
3886
3987
  rollupOptions: {
3887
3988
  input: viteUserConfig.build?.rollupOptions?.input ?? virtual.serverBuild.id
3888
3989
  }
3889
- })
3990
+ }
3890
3991
  });
3891
3992
  }
3892
3993
  return environmentOptionsResolvers;
3893
3994
  }
3894
- async function getEnvironmentOptions(ctx, environmentName, resolverOptions) {
3895
- let buildManifest = await getBuildManifest(ctx);
3896
- let environmentResolvers = await getEnvironmentOptionsResolvers(
3995
+ function resolveEnvironmentsOptions(environmentResolvers, resolverOptions) {
3996
+ let environmentOptions = {};
3997
+ for (let [environmentName, resolver] of Object.entries(
3998
+ environmentResolvers
3999
+ )) {
4000
+ environmentOptions[environmentName] = resolver(resolverOptions);
4001
+ }
4002
+ return environmentOptions;
4003
+ }
4004
+ async function getEnvironmentsOptions(ctx, buildManifest, viteCommand, resolverOptions) {
4005
+ let environmentOptionsResolvers = await getEnvironmentOptionsResolvers(
3897
4006
  ctx,
3898
- buildManifest
4007
+ buildManifest,
4008
+ viteCommand
4009
+ );
4010
+ return resolveEnvironmentsOptions(
4011
+ environmentOptionsResolvers,
4012
+ resolverOptions
3899
4013
  );
3900
- let resolver = environmentResolvers[environmentName];
3901
- invariant(resolver, `Missing environment resolver for ${environmentName}`);
3902
- return resolver(resolverOptions);
3903
4014
  }
3904
4015
  function isNonNullable(x) {
3905
4016
  return x != null;