@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/cli/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * @react-router/dev v0.0.0-experimental-902325fda
3
+ * @react-router/dev v0.0.0-experimental-004e483a8
4
4
  *
5
5
  * Copyright (c) Remix Software Inc.
6
6
  *
@@ -178,7 +178,7 @@ function validateRouteConfig({
178
178
  `Route config in "${routeConfigFile}" is invalid.`,
179
179
  root ? `${root}` : [],
180
180
  nested ? Object.entries(nested).map(
181
- ([path10, message]) => `Path: routes.${path10}
181
+ ([path9, message]) => `Path: routes.${path9}
182
182
  ${message}`
183
183
  ) : []
184
184
  ].flat().join("\n\n")
@@ -390,7 +390,8 @@ async function resolveConfig({
390
390
  }
391
391
  let future = {
392
392
  unstable_optimizeDeps: reactRouterUserConfig.future?.unstable_optimizeDeps ?? false,
393
- unstable_splitRouteModules: reactRouterUserConfig.future?.unstable_splitRouteModules ?? false
393
+ unstable_splitRouteModules: reactRouterUserConfig.future?.unstable_splitRouteModules ?? false,
394
+ unstable_viteEnvironmentApi: reactRouterUserConfig.future?.unstable_viteEnvironmentApi ?? false
394
395
  };
395
396
  let reactRouterConfig = deepFreeze({
396
397
  appDirectory,
@@ -635,6 +636,25 @@ var init_profiler = __esm({
635
636
  }
636
637
  });
637
638
 
639
+ // vite/babel.ts
640
+ var babel_exports = {};
641
+ __export(babel_exports, {
642
+ generate: () => generate,
643
+ parse: () => import_parser.parse,
644
+ t: () => t,
645
+ traverse: () => traverse
646
+ });
647
+ var import_parser, t, traverse, generate;
648
+ var init_babel = __esm({
649
+ "vite/babel.ts"() {
650
+ "use strict";
651
+ import_parser = require("@babel/parser");
652
+ t = __toESM(require("@babel/types"));
653
+ traverse = require("@babel/traverse").default;
654
+ generate = require("@babel/generator").default;
655
+ }
656
+ });
657
+
638
658
  // typegen/paths.ts
639
659
  function getTypesDir(ctx) {
640
660
  return Path2.join(ctx.rootDirectory, ".react-router/types");
@@ -657,7 +677,7 @@ var init_paths = __esm({
657
677
  });
658
678
 
659
679
  // typegen/generate.ts
660
- function generate(ctx, route) {
680
+ function generate2(ctx, route) {
661
681
  const lineage = getRouteLineage(ctx.config.routes, route);
662
682
  const urlpath = lineage.map((route2) => route2.path).join("/");
663
683
  const typesPath = getTypesPath(ctx, route);
@@ -765,7 +785,7 @@ var init_generate = __esm({
765
785
  Path3 = __toESM(require("pathe"));
766
786
  Pathe2 = __toESM(require("pathe/utils"));
767
787
  init_paths();
768
- noExtension = (path10) => Path3.join(Path3.dirname(path10), Pathe2.filename(path10));
788
+ noExtension = (path9) => Path3.join(Path3.dirname(path9), Pathe2.filename(path9));
769
789
  }
770
790
  });
771
791
 
@@ -817,36 +837,92 @@ async function writeAll(ctx) {
817
837
  import_node_fs3.default.rmSync(typegenDir, { recursive: true, force: true });
818
838
  Object.values(ctx.config.routes).forEach((route) => {
819
839
  const typesPath = getTypesPath(ctx, route);
820
- const content = generate(ctx, route);
840
+ const content = generate2(ctx, route);
821
841
  import_node_fs3.default.mkdirSync(Path4.dirname(typesPath), { recursive: true });
822
842
  import_node_fs3.default.writeFileSync(typesPath, content);
823
843
  });
844
+ const registerPath = Path4.join(typegenDir, "+register.ts");
845
+ import_node_fs3.default.writeFileSync(registerPath, register(ctx));
824
846
  }
825
- var import_node_fs3, Path4, import_picocolors3;
847
+ function register(ctx) {
848
+ const register2 = import_dedent2.default`
849
+ import "react-router";
850
+
851
+ declare module "react-router" {
852
+ interface Register {
853
+ params: Params;
854
+ }
855
+ }
856
+ `;
857
+ const { t: t2 } = babel_exports;
858
+ const typeParams = t2.tsTypeAliasDeclaration(
859
+ t2.identifier("Params"),
860
+ null,
861
+ t2.tsTypeLiteral(
862
+ Object.values(ctx.config.routes).map((route) => {
863
+ const lineage = getRouteLineage2(ctx.config.routes, route);
864
+ const fullpath = lineage.map((route2) => route2.path).join("/");
865
+ const params = parseParams2(fullpath);
866
+ return t2.tsPropertySignature(
867
+ t2.stringLiteral(fullpath),
868
+ t2.tsTypeAnnotation(
869
+ t2.tsTypeLiteral(
870
+ Object.entries(params).map(([param, isRequired]) => {
871
+ const property = t2.tsPropertySignature(
872
+ t2.stringLiteral(param),
873
+ t2.tsTypeAnnotation(t2.tsStringKeyword())
874
+ );
875
+ property.optional = !isRequired;
876
+ return property;
877
+ })
878
+ )
879
+ )
880
+ );
881
+ })
882
+ )
883
+ );
884
+ return [register2, generate(typeParams).code].join("\n\n");
885
+ }
886
+ function parseParams2(fullpath) {
887
+ const result = {};
888
+ let segments = fullpath.split("/");
889
+ segments.forEach((segment) => {
890
+ const match = segment.match(/^:([\w-]+)(\?)?/);
891
+ if (!match) return;
892
+ const param = match[1];
893
+ const isRequired = match[2] === void 0;
894
+ result[param] ||= isRequired;
895
+ return;
896
+ });
897
+ const hasSplat = segments.at(-1) === "*";
898
+ if (hasSplat) result["*"] = true;
899
+ return result;
900
+ }
901
+ function getRouteLineage2(routes2, route) {
902
+ const result = [];
903
+ while (route) {
904
+ result.push(route);
905
+ if (!route.parentId) break;
906
+ route = routes2[route.parentId];
907
+ }
908
+ result.reverse();
909
+ return result;
910
+ }
911
+ var import_node_fs3, import_dedent2, Path4, import_picocolors3;
826
912
  var init_typegen = __esm({
827
913
  "typegen/index.ts"() {
828
914
  "use strict";
829
915
  import_node_fs3 = __toESM(require("fs"));
916
+ import_dedent2 = __toESM(require("dedent"));
830
917
  Path4 = __toESM(require("pathe"));
831
918
  import_picocolors3 = __toESM(require("picocolors"));
832
919
  init_config();
920
+ init_babel();
833
921
  init_generate();
834
922
  init_paths();
835
923
  }
836
924
  });
837
925
 
838
- // vite/babel.ts
839
- var import_parser, t, traverse, generate2;
840
- var init_babel = __esm({
841
- "vite/babel.ts"() {
842
- "use strict";
843
- import_parser = require("@babel/parser");
844
- t = __toESM(require("@babel/types"));
845
- traverse = require("@babel/traverse").default;
846
- generate2 = require("@babel/generator").default;
847
- }
848
- });
849
-
850
926
  // vite/node-adapter.ts
851
927
  var import_node_events, import_node_stream, import_set_cookie_parser, import_node;
852
928
  var init_node_adapter = __esm({
@@ -970,11 +1046,11 @@ var init_route_chunks = __esm({
970
1046
  });
971
1047
 
972
1048
  // vite/with-props.ts
973
- var import_dedent2, vmod;
1049
+ var import_dedent3, vmod;
974
1050
  var init_with_props = __esm({
975
1051
  "vite/with-props.ts"() {
976
1052
  "use strict";
977
- import_dedent2 = __toESM(require("dedent"));
1053
+ import_dedent3 = __toESM(require("dedent"));
978
1054
  init_babel();
979
1055
  init_virtual_module();
980
1056
  vmod = create("with-props");
@@ -985,11 +1061,12 @@ var init_with_props = __esm({
985
1061
  async function resolveViteConfig({
986
1062
  configFile,
987
1063
  mode,
988
- root
1064
+ root,
1065
+ plugins
989
1066
  }) {
990
1067
  let vite2 = getVite();
991
1068
  let viteConfig = await vite2.resolveConfig(
992
- { mode, configFile, root },
1069
+ { mode, configFile, root, plugins },
993
1070
  "build",
994
1071
  // command
995
1072
  "production",
@@ -1005,6 +1082,17 @@ async function resolveViteConfig({
1005
1082
  async function extractPluginContext(viteConfig) {
1006
1083
  return viteConfig["__reactRouterPluginContext"];
1007
1084
  }
1085
+ function isSeverBundleEnvironmentName(name) {
1086
+ return name.startsWith(SSR_BUNDLE_PREFIX);
1087
+ }
1088
+ function getServerEnvironmentEntries(record, buildManifest) {
1089
+ return Object.entries(record).filter(
1090
+ ([name]) => buildManifest.serverBundles ? isSeverBundleEnvironmentName(name) : name === "ssr"
1091
+ );
1092
+ }
1093
+ function getServerEnvironmentKeys(record, buildManifest) {
1094
+ return getServerEnvironmentEntries(record, buildManifest).map(([key]) => key);
1095
+ }
1008
1096
  function getAddressableRoutes(routes2) {
1009
1097
  let nonAddressableIds = /* @__PURE__ */ new Set();
1010
1098
  for (let id in routes2) {
@@ -1054,6 +1142,39 @@ function getRoutesByServerBundleId(buildManifest) {
1054
1142
  }
1055
1143
  return routesByServerBundleId;
1056
1144
  }
1145
+ async function cleanBuildDirectory(viteConfig, ctx) {
1146
+ let buildDirectory = ctx.reactRouterConfig.buildDirectory;
1147
+ let isWithinRoot = () => {
1148
+ let relativePath = path7.relative(ctx.rootDirectory, buildDirectory);
1149
+ return !relativePath.startsWith("..") && !path7.isAbsolute(relativePath);
1150
+ };
1151
+ if (viteConfig.build.emptyOutDir ?? isWithinRoot()) {
1152
+ await fse.remove(buildDirectory);
1153
+ }
1154
+ }
1155
+ async function cleanViteManifests(environmentsOptions, ctx) {
1156
+ let viteManifestPaths = Object.entries(environmentsOptions).map(
1157
+ ([environmentName, options]) => {
1158
+ let outDir = options.build?.outDir;
1159
+ invariant(outDir, `Expected build.outDir for ${environmentName}`);
1160
+ return path7.join(outDir, ".vite/manifest.json");
1161
+ }
1162
+ );
1163
+ await Promise.all(
1164
+ viteManifestPaths.map(async (viteManifestPath) => {
1165
+ let manifestExists = await fse.pathExists(viteManifestPath);
1166
+ if (!manifestExists) return;
1167
+ if (!ctx.viteManifestEnabled) {
1168
+ await fse.remove(viteManifestPath);
1169
+ }
1170
+ let viteDir = path7.dirname(viteManifestPath);
1171
+ let viteDirFiles = await fse.readdir(viteDir);
1172
+ if (viteDirFiles.length === 0) {
1173
+ await fse.remove(viteDir);
1174
+ }
1175
+ })
1176
+ );
1177
+ }
1057
1178
  async function getBuildManifest(ctx) {
1058
1179
  let { routes: routes2, serverBundles, appDirectory } = ctx.reactRouterConfig;
1059
1180
  if (!serverBundles) {
@@ -1113,77 +1234,101 @@ async function getBuildManifest(ctx) {
1113
1234
  );
1114
1235
  return buildManifest;
1115
1236
  }
1116
- function mergeBuildOptions(base, overrides) {
1237
+ function mergeEnvironmentOptions(base, ...overrides) {
1117
1238
  let vite2 = getVite();
1118
- return vite2.mergeConfig({ build: base }, { build: overrides }).build;
1239
+ return overrides.reduce(
1240
+ (merged, override) => vite2.mergeConfig(merged, override, false),
1241
+ base
1242
+ );
1119
1243
  }
1120
- async function getEnvironmentOptionsResolvers(ctx, buildManifest) {
1244
+ async function getEnvironmentOptionsResolvers(ctx, buildManifest, viteCommand) {
1121
1245
  let { serverBuildFile, serverModuleFormat } = ctx.reactRouterConfig;
1122
- function getBaseBuildOptions({
1246
+ let packageRoot = path7.dirname(
1247
+ require.resolve("@react-router/dev/package.json")
1248
+ );
1249
+ let { moduleSyncEnabled } = await import(`file:///${path7.join(packageRoot, "module-sync-enabled/index.mjs")}`);
1250
+ let vite2 = getVite();
1251
+ let viteServerConditions = [
1252
+ ...vite2.defaultServerConditions ?? [],
1253
+ ...moduleSyncEnabled ? ["module-sync"] : []
1254
+ ];
1255
+ function getBaseOptions({
1123
1256
  viteUserConfig
1124
1257
  }) {
1125
1258
  return {
1126
- cssMinify: viteUserConfig.build?.cssMinify ?? true,
1127
- manifest: true,
1128
- // The manifest is enabled for all builds to detect SSR-only assets
1129
- rollupOptions: {
1130
- preserveEntrySignatures: "exports-only",
1131
- // Silence Rollup "use client" warnings
1132
- // Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
1133
- onwarn(warning, defaultHandler) {
1134
- if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
1135
- return;
1136
- }
1137
- let userHandler = viteUserConfig.build?.rollupOptions?.onwarn;
1138
- if (userHandler) {
1139
- userHandler(warning, defaultHandler);
1140
- } else {
1141
- defaultHandler(warning);
1259
+ build: {
1260
+ cssMinify: viteUserConfig.build?.cssMinify ?? true,
1261
+ manifest: true,
1262
+ // The manifest is enabled for all builds to detect SSR-only assets
1263
+ rollupOptions: {
1264
+ preserveEntrySignatures: "exports-only",
1265
+ // Silence Rollup "use client" warnings
1266
+ // Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
1267
+ onwarn(warning, defaultHandler) {
1268
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
1269
+ return;
1270
+ }
1271
+ let userHandler = viteUserConfig.build?.rollupOptions?.onwarn;
1272
+ if (userHandler) {
1273
+ userHandler(warning, defaultHandler);
1274
+ } else {
1275
+ defaultHandler(warning);
1276
+ }
1142
1277
  }
1143
1278
  }
1144
1279
  }
1145
1280
  };
1146
1281
  }
1147
- function getBaseServerBuildOptions({
1282
+ function getBaseServerOptions({
1148
1283
  viteUserConfig
1149
1284
  }) {
1150
- return mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
1151
- // We move SSR-only assets to client assets. Note that the
1152
- // SSR build can also emit code-split JS files (e.g. by
1153
- // dynamic import) under the same assets directory
1154
- // regardless of "ssrEmitAssets" option, so we also need to
1155
- // keep these JS files have to be kept as-is.
1156
- ssrEmitAssets: true,
1157
- copyPublicDir: false,
1158
- // Assets in the public directory are only used by the client
1159
- rollupOptions: {
1160
- output: {
1161
- entryFileNames: serverBuildFile,
1162
- format: serverModuleFormat
1285
+ let conditions = viteCommand === "build" ? viteServerConditions : ["development", ...viteServerConditions];
1286
+ return mergeEnvironmentOptions(getBaseOptions({ viteUserConfig }), {
1287
+ resolve: {
1288
+ external: ssrExternals,
1289
+ conditions,
1290
+ externalConditions: conditions
1291
+ },
1292
+ build: {
1293
+ // We move SSR-only assets to client assets. Note that the
1294
+ // SSR build can also emit code-split JS files (e.g. by
1295
+ // dynamic import) under the same assets directory
1296
+ // regardless of "ssrEmitAssets" option, so we also need to
1297
+ // keep these JS files have to be kept as-is.
1298
+ ssrEmitAssets: true,
1299
+ copyPublicDir: false,
1300
+ // Assets in the public directory are only used by the client
1301
+ rollupOptions: {
1302
+ output: {
1303
+ entryFileNames: serverBuildFile,
1304
+ format: serverModuleFormat
1305
+ }
1163
1306
  }
1164
1307
  }
1165
1308
  });
1166
1309
  }
1167
1310
  let environmentOptionsResolvers = {
1168
- client: ({ viteUserConfig }) => ({
1169
- build: mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
1311
+ client: ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseOptions({ viteUserConfig }), {
1312
+ build: {
1170
1313
  rollupOptions: {
1171
1314
  input: [
1172
1315
  ctx.entryClientFilePath,
1173
- ...Object.values(ctx.reactRouterConfig.routes).flatMap((route) => {
1174
- let routeFilePath = path7.resolve(
1175
- ctx.reactRouterConfig.appDirectory,
1176
- route.file
1177
- );
1178
- let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
1179
- let code = fse.readFileSync(routeFilePath, "utf-8");
1180
- return [
1181
- `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
1182
- ...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
1183
- (exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
1184
- ) : []
1185
- ].filter(isNonNullable);
1186
- })
1316
+ ...Object.values(ctx.reactRouterConfig.routes).flatMap(
1317
+ (route) => {
1318
+ let routeFilePath = path7.resolve(
1319
+ ctx.reactRouterConfig.appDirectory,
1320
+ route.file
1321
+ );
1322
+ let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
1323
+ let code = fse.readFileSync(routeFilePath, "utf-8");
1324
+ return [
1325
+ `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
1326
+ ...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
1327
+ (exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
1328
+ ) : []
1329
+ ].filter(isNonNullable);
1330
+ }
1331
+ )
1187
1332
  ],
1188
1333
  output: {
1189
1334
  entryFileNames({ moduleIds }) {
@@ -1195,19 +1340,19 @@ async function getEnvironmentOptionsResolvers(ctx, buildManifest) {
1195
1340
  }
1196
1341
  },
1197
1342
  outDir: getClientBuildDirectory(ctx.reactRouterConfig)
1198
- })
1343
+ }
1199
1344
  })
1200
1345
  };
1201
1346
  if (hasServerBundles(buildManifest)) {
1202
1347
  for (let [serverBundleId, routes2] of Object.entries(
1203
1348
  getRoutesByServerBundleId(buildManifest)
1204
1349
  )) {
1205
- environmentOptionsResolvers[`ssr-bundle-${serverBundleId}`] = ({
1206
- viteUserConfig
1207
- }) => ({
1208
- build: mergeBuildOptions(
1209
- getBaseServerBuildOptions({ viteUserConfig }),
1210
- {
1350
+ const serverBundleEnvironmentId = serverBundleId.replaceAll("-", "_");
1351
+ const environmentName = `${SSR_BUNDLE_PREFIX}${serverBundleEnvironmentId}`;
1352
+ environmentOptionsResolvers[environmentName] = ({ viteUserConfig }) => mergeEnvironmentOptions(
1353
+ getBaseServerOptions({ viteUserConfig }),
1354
+ {
1355
+ build: {
1211
1356
  outDir: getServerBuildDirectory(ctx, { serverBundleId }),
1212
1357
  rollupOptions: {
1213
1358
  input: `${virtual.serverBuild.id}?route-ids=${Object.keys(
@@ -1215,25 +1360,37 @@ async function getEnvironmentOptionsResolvers(ctx, buildManifest) {
1215
1360
  ).join(",")}`
1216
1361
  }
1217
1362
  }
1218
- )
1219
- });
1363
+ },
1364
+ // Ensure server bundle environments extend the user's SSR
1365
+ // environment config if it exists
1366
+ viteUserConfig.environments?.ssr ?? {}
1367
+ );
1220
1368
  }
1221
1369
  } else {
1222
- environmentOptionsResolvers.ssr = ({ viteUserConfig }) => ({
1223
- build: mergeBuildOptions(getBaseServerBuildOptions({ viteUserConfig }), {
1370
+ environmentOptionsResolvers.ssr = ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseServerOptions({ viteUserConfig }), {
1371
+ build: {
1224
1372
  outDir: getServerBuildDirectory(ctx),
1225
1373
  rollupOptions: {
1226
1374
  input: viteUserConfig.build?.rollupOptions?.input ?? virtual.serverBuild.id
1227
1375
  }
1228
- })
1376
+ }
1229
1377
  });
1230
1378
  }
1231
1379
  return environmentOptionsResolvers;
1232
1380
  }
1381
+ function resolveEnvironmentsOptions(environmentResolvers, resolverOptions) {
1382
+ let environmentOptions = {};
1383
+ for (let [environmentName, resolver] of Object.entries(
1384
+ environmentResolvers
1385
+ )) {
1386
+ environmentOptions[environmentName] = resolver(resolverOptions);
1387
+ }
1388
+ return environmentOptions;
1389
+ }
1233
1390
  function isNonNullable(x) {
1234
1391
  return x != null;
1235
1392
  }
1236
- var import_node_crypto, path7, url, fse, babel2, import_react_router2, import_es_module_lexer, import_pick3, import_jsesc, import_picocolors4, import_kebabCase, BUILD_CLIENT_ROUTE_QUERY_STRING, virtualHmrRuntime, virtualInjectHmrRuntime, virtual, getServerBuildDirectory, getClientBuildDirectory, defaultEntriesDir, defaultEntries, REACT_REFRESH_HEADER;
1393
+ var import_node_crypto, path7, url, fse, babel2, import_react_router2, import_es_module_lexer, import_pick3, import_jsesc, import_picocolors4, import_kebabCase, BUILD_CLIENT_ROUTE_QUERY_STRING, SSR_BUNDLE_PREFIX, virtualHmrRuntime, virtualInjectHmrRuntime, virtual, getServerBuildDirectory, getClientBuildDirectory, defaultEntriesDir, defaultEntries, REACT_REFRESH_HEADER;
1237
1394
  var init_plugin = __esm({
1238
1395
  "vite/plugin.ts"() {
1239
1396
  "use strict";
@@ -1262,6 +1419,7 @@ var init_plugin = __esm({
1262
1419
  init_config();
1263
1420
  init_with_props();
1264
1421
  BUILD_CLIENT_ROUTE_QUERY_STRING = "?__react-router-build-client-route";
1422
+ SSR_BUNDLE_PREFIX = "ssrBundle_";
1265
1423
  virtualHmrRuntime = create("hmr-runtime");
1266
1424
  virtualInjectHmrRuntime = create("inject-hmr-runtime");
1267
1425
  virtual = {
@@ -1312,34 +1470,83 @@ var build_exports = {};
1312
1470
  __export(build_exports, {
1313
1471
  build: () => build
1314
1472
  });
1315
- async function cleanBuildDirectory(viteConfig, ctx) {
1316
- let buildDirectory = ctx.reactRouterConfig.buildDirectory;
1317
- let isWithinRoot = () => {
1318
- let relativePath = import_node_path2.default.relative(ctx.rootDirectory, buildDirectory);
1319
- return !relativePath.startsWith("..") && !import_node_path2.default.isAbsolute(relativePath);
1320
- };
1321
- if (viteConfig.build.emptyOutDir ?? isWithinRoot()) {
1322
- await import_fs_extra.default.remove(buildDirectory);
1473
+ async function build(root, viteBuildOptions) {
1474
+ await preloadVite();
1475
+ let vite2 = getVite();
1476
+ let configResult = await loadConfig({ rootDirectory: root });
1477
+ if (!configResult.ok) {
1478
+ throw new Error(configResult.error);
1479
+ }
1480
+ let config = configResult.value;
1481
+ let unstable_viteEnvironmentApi = config.future.unstable_viteEnvironmentApi;
1482
+ let viteMajor = parseInt(vite2.version.split(".")[0], 10);
1483
+ if (unstable_viteEnvironmentApi && viteMajor === 5) {
1484
+ throw new Error(
1485
+ "The future.unstable_viteEnvironmentApi option is not supported in Vite 5"
1486
+ );
1323
1487
  }
1488
+ return await (unstable_viteEnvironmentApi ? viteAppBuild(root, viteBuildOptions) : viteBuild(root, viteBuildOptions));
1324
1489
  }
1325
- function getViteManifestPaths(environmentOptionsResolvers) {
1326
- return Object.entries(environmentOptionsResolvers).map(
1327
- ([environmentName, resolveOptions]) => {
1328
- invariant(
1329
- resolveOptions,
1330
- `Expected build environment options resolver for ${environmentName}`
1331
- );
1332
- let options = resolveOptions({
1333
- viteCommand: "build",
1334
- viteUserConfig: {}
1335
- });
1336
- let outDir = options.build.outDir;
1337
- invariant(outDir, `Expected build.outDir for ${environmentName}`);
1338
- return import_node_path2.default.join(outDir, ".vite/manifest.json");
1339
- }
1340
- );
1490
+ async function viteAppBuild(root, {
1491
+ assetsInlineLimit,
1492
+ clearScreen,
1493
+ config: configFile,
1494
+ emptyOutDir,
1495
+ force,
1496
+ logLevel,
1497
+ minify,
1498
+ mode,
1499
+ sourcemapClient,
1500
+ sourcemapServer
1501
+ }) {
1502
+ let vite2 = getVite();
1503
+ let builder = await vite2.createBuilder({
1504
+ root,
1505
+ mode,
1506
+ configFile,
1507
+ build: {
1508
+ assetsInlineLimit,
1509
+ emptyOutDir,
1510
+ minify
1511
+ },
1512
+ optimizeDeps: { force },
1513
+ clearScreen,
1514
+ logLevel,
1515
+ plugins: [
1516
+ {
1517
+ name: "react-router:cli-config",
1518
+ configEnvironment(name) {
1519
+ if (sourcemapClient && name === "client") {
1520
+ return {
1521
+ build: {
1522
+ sourcemap: sourcemapClient
1523
+ }
1524
+ };
1525
+ }
1526
+ if (sourcemapServer && name !== "client") {
1527
+ return {
1528
+ build: {
1529
+ sourcemap: sourcemapServer
1530
+ }
1531
+ };
1532
+ }
1533
+ },
1534
+ configResolved(config) {
1535
+ let hasReactRouterPlugin = config.plugins.find(
1536
+ (plugin2) => plugin2.name === "react-router"
1537
+ );
1538
+ if (!hasReactRouterPlugin) {
1539
+ throw new Error(
1540
+ "React Router Vite plugin not found in Vite config"
1541
+ );
1542
+ }
1543
+ }
1544
+ }
1545
+ ]
1546
+ });
1547
+ await builder.buildApp();
1341
1548
  }
1342
- async function build(root, {
1549
+ async function viteBuild(root, {
1343
1550
  assetsInlineLimit,
1344
1551
  clearScreen,
1345
1552
  config: configFile,
@@ -1351,24 +1558,32 @@ async function build(root, {
1351
1558
  sourcemapClient,
1352
1559
  sourcemapServer
1353
1560
  }) {
1354
- await preloadVite();
1355
- let viteConfig = await resolveViteConfig({ configFile, mode, root });
1356
- const ctx = await extractPluginContext(viteConfig);
1561
+ let viteUserConfig = {};
1562
+ let viteConfig = await resolveViteConfig({
1563
+ configFile,
1564
+ mode,
1565
+ root,
1566
+ plugins: [
1567
+ {
1568
+ name: "react-router:extract-vite-user-config",
1569
+ config(config) {
1570
+ viteUserConfig = config;
1571
+ }
1572
+ }
1573
+ ]
1574
+ });
1575
+ let ctx = await extractPluginContext(viteConfig);
1357
1576
  if (!ctx) {
1358
1577
  console.error(
1359
1578
  import_picocolors5.default.red("React Router Vite plugin not found in Vite config")
1360
1579
  );
1361
1580
  process.exit(1);
1362
1581
  }
1363
- let { reactRouterConfig } = ctx;
1364
- let vite2 = getVite();
1365
- async function viteBuild(environmentOptionsResolvers2, environmentName) {
1582
+ async function buildEnvironment(environmentName) {
1583
+ let vite2 = getVite();
1366
1584
  let ssr = environmentName !== "client";
1367
- let resolveOptions = environmentOptionsResolvers2[environmentName];
1368
- invariant(
1369
- resolveOptions,
1370
- `Missing environment options resolver for ${environmentName}`
1371
- );
1585
+ let resolveOptions = environmentOptionsResolvers[environmentName];
1586
+ invariant(resolveOptions);
1372
1587
  let environmentBuildContext = {
1373
1588
  name: environmentName,
1374
1589
  resolveOptions
@@ -1390,49 +1605,37 @@ async function build(root, {
1390
1605
  ...{ __reactRouterEnvironmentBuildContext: environmentBuildContext }
1391
1606
  });
1392
1607
  }
1393
- await cleanBuildDirectory(viteConfig, ctx);
1608
+ let { reactRouterConfig } = ctx;
1394
1609
  let buildManifest = await getBuildManifest(ctx);
1395
1610
  let environmentOptionsResolvers = await getEnvironmentOptionsResolvers(
1396
1611
  ctx,
1397
- buildManifest
1612
+ buildManifest,
1613
+ "build"
1398
1614
  );
1399
- await viteBuild(environmentOptionsResolvers, "client");
1400
- let serverEnvironmentNames = Object.keys(
1401
- environmentOptionsResolvers
1402
- ).filter((environmentName) => environmentName !== "client");
1403
- await Promise.all(
1404
- serverEnvironmentNames.map(
1405
- (environmentName) => viteBuild(environmentOptionsResolvers, environmentName)
1406
- )
1615
+ let environmentsOptions = resolveEnvironmentsOptions(
1616
+ environmentOptionsResolvers,
1617
+ { viteUserConfig }
1407
1618
  );
1408
- let viteManifestPaths = getViteManifestPaths(environmentOptionsResolvers);
1409
- await Promise.all(
1410
- viteManifestPaths.map(async (viteManifestPath) => {
1411
- let manifestExists = await import_fs_extra.default.pathExists(viteManifestPath);
1412
- if (!manifestExists) return;
1413
- if (!ctx.viteManifestEnabled) {
1414
- await import_fs_extra.default.remove(viteManifestPath);
1415
- }
1416
- let viteDir = import_node_path2.default.dirname(viteManifestPath);
1417
- let viteDirFiles = await import_fs_extra.default.readdir(viteDir);
1418
- if (viteDirFiles.length === 0) {
1419
- await import_fs_extra.default.remove(viteDir);
1420
- }
1421
- })
1619
+ await cleanBuildDirectory(viteConfig, ctx);
1620
+ await buildEnvironment("client");
1621
+ let serverEnvironmentNames = getServerEnvironmentKeys(
1622
+ environmentOptionsResolvers,
1623
+ buildManifest
1422
1624
  );
1625
+ await Promise.all(serverEnvironmentNames.map(buildEnvironment));
1626
+ await cleanViteManifests(environmentsOptions, ctx);
1423
1627
  await reactRouterConfig.buildEnd?.({
1424
1628
  buildManifest,
1425
1629
  reactRouterConfig,
1426
1630
  viteConfig
1427
1631
  });
1428
1632
  }
1429
- var import_node_path2, import_fs_extra, import_picocolors5;
1633
+ var import_picocolors5;
1430
1634
  var init_build = __esm({
1431
1635
  "vite/build.ts"() {
1432
1636
  "use strict";
1433
- import_node_path2 = __toESM(require("path"));
1434
- import_fs_extra = __toESM(require("fs-extra"));
1435
1637
  import_picocolors5 = __toESM(require("picocolors"));
1638
+ init_config();
1436
1639
  init_plugin();
1437
1640
  init_invariant();
1438
1641
  init_vite();
@@ -1508,8 +1711,8 @@ var import_semver = __toESM(require("semver"));
1508
1711
  var import_picocolors8 = __toESM(require("picocolors"));
1509
1712
 
1510
1713
  // cli/commands.ts
1511
- var path9 = __toESM(require("path"));
1512
- var import_fs_extra2 = __toESM(require("fs-extra"));
1714
+ var path8 = __toESM(require("path"));
1715
+ var import_fs_extra = __toESM(require("fs-extra"));
1513
1716
  var import_package_json2 = __toESM(require("@npmcli/package-json"));
1514
1717
  var import_exit_hook = __toESM(require("exit-hook"));
1515
1718
  var import_picocolors7 = __toESM(require("picocolors"));
@@ -1662,14 +1865,14 @@ async function generateEntry(entry, reactRouterRoot, flags = {}) {
1662
1865
  console.error(import_picocolors7.default.red(`No default server entry detected.`));
1663
1866
  return;
1664
1867
  }
1665
- let defaultsDirectory = path9.resolve(
1666
- path9.dirname(require.resolve("@react-router/dev/package.json")),
1868
+ let defaultsDirectory = path8.resolve(
1869
+ path8.dirname(require.resolve("@react-router/dev/package.json")),
1667
1870
  "dist",
1668
1871
  "config",
1669
1872
  "defaults"
1670
1873
  );
1671
- let defaultEntryClient = path9.resolve(defaultsDirectory, "entry.client.tsx");
1672
- let defaultEntryServer = path9.resolve(
1874
+ let defaultEntryClient = path8.resolve(defaultsDirectory, "entry.client.tsx");
1875
+ let defaultEntryServer = path8.resolve(
1673
1876
  defaultsDirectory,
1674
1877
  `entry.server.node.tsx`
1675
1878
  );
@@ -1678,19 +1881,19 @@ async function generateEntry(entry, reactRouterRoot, flags = {}) {
1678
1881
  let useTypeScript = flags.typescript ?? true;
1679
1882
  let outputExtension = useTypeScript ? "tsx" : "jsx";
1680
1883
  let outputEntry = `${entry}.${outputExtension}`;
1681
- let outputFile2 = path9.resolve(appDirectory, outputEntry);
1884
+ let outputFile2 = path8.resolve(appDirectory, outputEntry);
1682
1885
  if (!useTypeScript) {
1683
1886
  let javascript = transpile(contents, {
1684
1887
  cwd: rootDirectory,
1685
1888
  filename: isServerEntry ? defaultEntryServer : defaultEntryClient
1686
1889
  });
1687
- await import_fs_extra2.default.writeFile(outputFile2, javascript, "utf-8");
1890
+ await import_fs_extra.default.writeFile(outputFile2, javascript, "utf-8");
1688
1891
  } else {
1689
- await import_fs_extra2.default.writeFile(outputFile2, contents, "utf-8");
1892
+ await import_fs_extra.default.writeFile(outputFile2, contents, "utf-8");
1690
1893
  }
1691
1894
  console.log(
1692
1895
  import_picocolors7.default.blue(
1693
- `Entry file ${entry} created at ${path9.relative(
1896
+ `Entry file ${entry} created at ${path8.relative(
1694
1897
  rootDirectory,
1695
1898
  outputFile2
1696
1899
  )}.`
@@ -1699,10 +1902,10 @@ async function generateEntry(entry, reactRouterRoot, flags = {}) {
1699
1902
  }
1700
1903
  async function checkForEntry(rootDirectory, appDirectory, entries2) {
1701
1904
  for (let entry of entries2) {
1702
- let entryPath = path9.resolve(appDirectory, entry);
1703
- let exists = await import_fs_extra2.default.pathExists(entryPath);
1905
+ let entryPath = path8.resolve(appDirectory, entry);
1906
+ let exists = await import_fs_extra.default.pathExists(entryPath);
1704
1907
  if (exists) {
1705
- let relative8 = path9.relative(rootDirectory, entryPath);
1908
+ let relative8 = path8.relative(rootDirectory, entryPath);
1706
1909
  console.error(import_picocolors7.default.red(`Entry file ${relative8} already exists.`));
1707
1910
  return process.exit(1);
1708
1911
  }
@@ -1710,12 +1913,12 @@ async function checkForEntry(rootDirectory, appDirectory, entries2) {
1710
1913
  }
1711
1914
  async function createServerEntry(rootDirectory, appDirectory, inputFile) {
1712
1915
  await checkForEntry(rootDirectory, appDirectory, serverEntries);
1713
- let contents = await import_fs_extra2.default.readFile(inputFile, "utf-8");
1916
+ let contents = await import_fs_extra.default.readFile(inputFile, "utf-8");
1714
1917
  return contents;
1715
1918
  }
1716
1919
  async function createClientEntry(rootDirectory, appDirectory, inputFile) {
1717
1920
  await checkForEntry(rootDirectory, appDirectory, clientEntries);
1718
- let contents = await import_fs_extra2.default.readFile(inputFile, "utf-8");
1921
+ let contents = await import_fs_extra.default.readFile(inputFile, "utf-8");
1719
1922
  return contents;
1720
1923
  }
1721
1924
  async function typegen(root, flags) {