@react-router/dev 7.1.5-pre.0 → 7.2.0-pre.0

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 v7.1.5-pre.0
3
+ * @react-router/dev v7.2.0-pre.0
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")
@@ -389,7 +389,9 @@ async function resolveConfig({
389
389
  );
390
390
  }
391
391
  let future = {
392
- unstable_optimizeDeps: reactRouterUserConfig.future?.unstable_optimizeDeps ?? false
392
+ unstable_optimizeDeps: reactRouterUserConfig.future?.unstable_optimizeDeps ?? false,
393
+ unstable_splitRouteModules: reactRouterUserConfig.future?.unstable_splitRouteModules ?? false,
394
+ unstable_viteEnvironmentApi: reactRouterUserConfig.future?.unstable_viteEnvironmentApi ?? false
393
395
  };
394
396
  let reactRouterConfig = deepFreeze({
395
397
  appDirectory,
@@ -764,7 +766,7 @@ var init_generate = __esm({
764
766
  Path3 = __toESM(require("pathe"));
765
767
  Pathe2 = __toESM(require("pathe/utils"));
766
768
  init_paths();
767
- noExtension = (path10) => Path3.join(Path3.dirname(path10), Pathe2.filename(path10));
769
+ noExtension = (path9) => Path3.join(Path3.dirname(path9), Pathe2.filename(path9));
768
770
  }
769
771
  });
770
772
 
@@ -915,6 +917,59 @@ var init_remove_exports = __esm({
915
917
  }
916
918
  });
917
919
 
920
+ // vite/cache.ts
921
+ var init_cache = __esm({
922
+ "vite/cache.ts"() {
923
+ "use strict";
924
+ }
925
+ });
926
+
927
+ // vite/route-chunks.ts
928
+ function getRouteChunkModuleId(filePath, chunkName) {
929
+ return `${filePath}${routeChunkQueryStrings[chunkName]}`;
930
+ }
931
+ function isRouteChunkModuleId(id) {
932
+ return Object.values(routeChunkQueryStrings).some(
933
+ (queryString) => id.endsWith(queryString)
934
+ );
935
+ }
936
+ function isRouteChunkName(name) {
937
+ return name === mainChunkName || routeChunkExportNames.includes(name);
938
+ }
939
+ function getRouteChunkNameFromModuleId(id) {
940
+ if (!isRouteChunkModuleId(id)) {
941
+ return null;
942
+ }
943
+ let chunkName = id.split(routeChunkQueryStringPrefix)[1].split("&")[0];
944
+ if (!isRouteChunkName(chunkName)) {
945
+ return null;
946
+ }
947
+ return chunkName;
948
+ }
949
+ var routeChunkExportNames, mainChunkName, routeChunkNames, routeChunkQueryStringPrefix, routeChunkQueryStrings;
950
+ var init_route_chunks = __esm({
951
+ "vite/route-chunks.ts"() {
952
+ "use strict";
953
+ init_invariant();
954
+ init_cache();
955
+ init_babel();
956
+ routeChunkExportNames = [
957
+ "clientAction",
958
+ "clientLoader",
959
+ "HydrateFallback"
960
+ ];
961
+ mainChunkName = "main";
962
+ routeChunkNames = ["main", ...routeChunkExportNames];
963
+ routeChunkQueryStringPrefix = "?route-chunk=";
964
+ routeChunkQueryStrings = {
965
+ main: `${routeChunkQueryStringPrefix}main`,
966
+ clientAction: `${routeChunkQueryStringPrefix}clientAction`,
967
+ clientLoader: `${routeChunkQueryStringPrefix}clientLoader`,
968
+ HydrateFallback: `${routeChunkQueryStringPrefix}HydrateFallback`
969
+ };
970
+ }
971
+ });
972
+
918
973
  // vite/with-props.ts
919
974
  var import_dedent2, vmod;
920
975
  var init_with_props = __esm({
@@ -931,11 +986,12 @@ var init_with_props = __esm({
931
986
  async function resolveViteConfig({
932
987
  configFile,
933
988
  mode,
934
- root
989
+ root,
990
+ plugins
935
991
  }) {
936
992
  let vite2 = getVite();
937
993
  let viteConfig = await vite2.resolveConfig(
938
- { mode, configFile, root },
994
+ { mode, configFile, root, plugins },
939
995
  "build",
940
996
  // command
941
997
  "production",
@@ -951,7 +1007,315 @@ async function resolveViteConfig({
951
1007
  async function extractPluginContext(viteConfig) {
952
1008
  return viteConfig["__reactRouterPluginContext"];
953
1009
  }
954
- var import_node_crypto, path7, url, fse, babel2, import_react_router2, import_es_module_lexer, import_jsesc, import_picocolors4, virtualHmrRuntime, virtualInjectHmrRuntime, virtual, getServerBuildDirectory, defaultEntriesDir, defaultEntries, REACT_REFRESH_HEADER;
1010
+ function isSeverBundleEnvironmentName(name) {
1011
+ return name.startsWith(SSR_BUNDLE_PREFIX);
1012
+ }
1013
+ function getServerEnvironmentEntries(record, buildManifest) {
1014
+ return Object.entries(record).filter(
1015
+ ([name]) => buildManifest.serverBundles ? isSeverBundleEnvironmentName(name) : name === "ssr"
1016
+ );
1017
+ }
1018
+ function getServerEnvironmentKeys(record, buildManifest) {
1019
+ return getServerEnvironmentEntries(record, buildManifest).map(([key]) => key);
1020
+ }
1021
+ function getAddressableRoutes(routes2) {
1022
+ let nonAddressableIds = /* @__PURE__ */ new Set();
1023
+ for (let id in routes2) {
1024
+ let route = routes2[id];
1025
+ if (route.index) {
1026
+ invariant(
1027
+ route.parentId,
1028
+ `Expected index route "${route.id}" to have "parentId" set`
1029
+ );
1030
+ nonAddressableIds.add(route.parentId);
1031
+ }
1032
+ if (typeof route.path !== "string" && !route.index) {
1033
+ nonAddressableIds.add(id);
1034
+ }
1035
+ }
1036
+ return Object.values(routes2).filter(
1037
+ (route) => !nonAddressableIds.has(route.id)
1038
+ );
1039
+ }
1040
+ function getRouteBranch(routes2, routeId) {
1041
+ let branch = [];
1042
+ let currentRouteId = routeId;
1043
+ while (currentRouteId) {
1044
+ let route = routes2[currentRouteId];
1045
+ invariant(route, `Missing route for ${currentRouteId}`);
1046
+ branch.push(route);
1047
+ currentRouteId = route.parentId;
1048
+ }
1049
+ return branch.reverse();
1050
+ }
1051
+ function hasServerBundles(buildManifest) {
1052
+ return Object.keys(buildManifest.serverBundles ?? {}).length > 0;
1053
+ }
1054
+ function getRoutesByServerBundleId(buildManifest) {
1055
+ if (!buildManifest.routeIdToServerBundleId) {
1056
+ return {};
1057
+ }
1058
+ let routesByServerBundleId = {};
1059
+ for (let [routeId, serverBundleId] of Object.entries(
1060
+ buildManifest.routeIdToServerBundleId
1061
+ )) {
1062
+ routesByServerBundleId[serverBundleId] ??= {};
1063
+ let branch = getRouteBranch(buildManifest.routes, routeId);
1064
+ for (let route of branch) {
1065
+ routesByServerBundleId[serverBundleId][route.id] = route;
1066
+ }
1067
+ }
1068
+ return routesByServerBundleId;
1069
+ }
1070
+ async function cleanBuildDirectory(viteConfig, ctx) {
1071
+ let buildDirectory = ctx.reactRouterConfig.buildDirectory;
1072
+ let isWithinRoot = () => {
1073
+ let relativePath = path7.relative(ctx.rootDirectory, buildDirectory);
1074
+ return !relativePath.startsWith("..") && !path7.isAbsolute(relativePath);
1075
+ };
1076
+ if (viteConfig.build.emptyOutDir ?? isWithinRoot()) {
1077
+ await fse.remove(buildDirectory);
1078
+ }
1079
+ }
1080
+ async function cleanViteManifests(environmentsOptions, ctx) {
1081
+ let viteManifestPaths = Object.entries(environmentsOptions).map(
1082
+ ([environmentName, options]) => {
1083
+ let outDir = options.build?.outDir;
1084
+ invariant(outDir, `Expected build.outDir for ${environmentName}`);
1085
+ return path7.join(outDir, ".vite/manifest.json");
1086
+ }
1087
+ );
1088
+ await Promise.all(
1089
+ viteManifestPaths.map(async (viteManifestPath) => {
1090
+ let manifestExists = await fse.pathExists(viteManifestPath);
1091
+ if (!manifestExists) return;
1092
+ if (!ctx.viteManifestEnabled) {
1093
+ await fse.remove(viteManifestPath);
1094
+ }
1095
+ let viteDir = path7.dirname(viteManifestPath);
1096
+ let viteDirFiles = await fse.readdir(viteDir);
1097
+ if (viteDirFiles.length === 0) {
1098
+ await fse.remove(viteDir);
1099
+ }
1100
+ })
1101
+ );
1102
+ }
1103
+ async function getBuildManifest(ctx) {
1104
+ let { routes: routes2, serverBundles, appDirectory } = ctx.reactRouterConfig;
1105
+ if (!serverBundles) {
1106
+ return { routes: routes2 };
1107
+ }
1108
+ let { normalizePath } = await import("vite");
1109
+ let serverBuildDirectory = getServerBuildDirectory(ctx);
1110
+ let resolvedAppDirectory = path7.resolve(ctx.rootDirectory, appDirectory);
1111
+ let rootRelativeRoutes = Object.fromEntries(
1112
+ Object.entries(routes2).map(([id, route]) => {
1113
+ let filePath = path7.join(resolvedAppDirectory, route.file);
1114
+ let rootRelativeFilePath = normalizePath(
1115
+ path7.relative(ctx.rootDirectory, filePath)
1116
+ );
1117
+ return [id, { ...route, file: rootRelativeFilePath }];
1118
+ })
1119
+ );
1120
+ let buildManifest = {
1121
+ serverBundles: {},
1122
+ routeIdToServerBundleId: {},
1123
+ routes: rootRelativeRoutes
1124
+ };
1125
+ await Promise.all(
1126
+ getAddressableRoutes(routes2).map(async (route) => {
1127
+ let branch = getRouteBranch(routes2, route.id);
1128
+ let serverBundleId = await serverBundles({
1129
+ branch: branch.map(
1130
+ (route2) => configRouteToBranchRoute({
1131
+ ...route2,
1132
+ // Ensure absolute paths are passed to the serverBundles function
1133
+ file: path7.join(resolvedAppDirectory, route2.file)
1134
+ })
1135
+ )
1136
+ });
1137
+ if (typeof serverBundleId !== "string") {
1138
+ throw new Error(`The "serverBundles" function must return a string`);
1139
+ }
1140
+ if (!/^[a-zA-Z0-9-_]+$/.test(serverBundleId)) {
1141
+ throw new Error(
1142
+ `The "serverBundles" function must only return strings containing alphanumeric characters, hyphens and underscores.`
1143
+ );
1144
+ }
1145
+ buildManifest.routeIdToServerBundleId[route.id] = serverBundleId;
1146
+ buildManifest.serverBundles[serverBundleId] ??= {
1147
+ id: serverBundleId,
1148
+ file: normalizePath(
1149
+ path7.join(
1150
+ path7.relative(
1151
+ ctx.rootDirectory,
1152
+ path7.join(serverBuildDirectory, serverBundleId)
1153
+ ),
1154
+ ctx.reactRouterConfig.serverBuildFile
1155
+ )
1156
+ )
1157
+ };
1158
+ })
1159
+ );
1160
+ return buildManifest;
1161
+ }
1162
+ function mergeEnvironmentOptions(base, ...overrides) {
1163
+ let vite2 = getVite();
1164
+ return overrides.reduce(
1165
+ (merged, override) => vite2.mergeConfig(merged, override, false),
1166
+ base
1167
+ );
1168
+ }
1169
+ async function getEnvironmentOptionsResolvers(ctx, buildManifest, viteCommand) {
1170
+ let { serverBuildFile, serverModuleFormat } = ctx.reactRouterConfig;
1171
+ let packageRoot = path7.dirname(
1172
+ require.resolve("@react-router/dev/package.json")
1173
+ );
1174
+ let { moduleSyncEnabled } = await import(`file:///${path7.join(packageRoot, "module-sync-enabled/index.mjs")}`);
1175
+ let vite2 = getVite();
1176
+ let viteServerConditions = [
1177
+ ...vite2.defaultServerConditions ?? [],
1178
+ ...moduleSyncEnabled ? ["module-sync"] : []
1179
+ ];
1180
+ function getBaseOptions({
1181
+ viteUserConfig
1182
+ }) {
1183
+ return {
1184
+ build: {
1185
+ cssMinify: viteUserConfig.build?.cssMinify ?? true,
1186
+ manifest: true,
1187
+ // The manifest is enabled for all builds to detect SSR-only assets
1188
+ rollupOptions: {
1189
+ preserveEntrySignatures: "exports-only",
1190
+ // Silence Rollup "use client" warnings
1191
+ // Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
1192
+ onwarn(warning, defaultHandler) {
1193
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
1194
+ return;
1195
+ }
1196
+ let userHandler = viteUserConfig.build?.rollupOptions?.onwarn;
1197
+ if (userHandler) {
1198
+ userHandler(warning, defaultHandler);
1199
+ } else {
1200
+ defaultHandler(warning);
1201
+ }
1202
+ }
1203
+ }
1204
+ }
1205
+ };
1206
+ }
1207
+ function getBaseServerOptions({
1208
+ viteUserConfig
1209
+ }) {
1210
+ let conditions = viteCommand === "build" ? viteServerConditions : ["development", ...viteServerConditions];
1211
+ return mergeEnvironmentOptions(getBaseOptions({ viteUserConfig }), {
1212
+ resolve: {
1213
+ external: ssrExternals,
1214
+ conditions,
1215
+ externalConditions: conditions
1216
+ },
1217
+ build: {
1218
+ // We move SSR-only assets to client assets. Note that the
1219
+ // SSR build can also emit code-split JS files (e.g. by
1220
+ // dynamic import) under the same assets directory
1221
+ // regardless of "ssrEmitAssets" option, so we also need to
1222
+ // keep these JS files have to be kept as-is.
1223
+ ssrEmitAssets: true,
1224
+ copyPublicDir: false,
1225
+ // Assets in the public directory are only used by the client
1226
+ rollupOptions: {
1227
+ output: {
1228
+ entryFileNames: serverBuildFile,
1229
+ format: serverModuleFormat
1230
+ }
1231
+ }
1232
+ }
1233
+ });
1234
+ }
1235
+ let environmentOptionsResolvers = {
1236
+ client: ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseOptions({ viteUserConfig }), {
1237
+ build: {
1238
+ rollupOptions: {
1239
+ input: [
1240
+ ctx.entryClientFilePath,
1241
+ ...Object.values(ctx.reactRouterConfig.routes).flatMap(
1242
+ (route) => {
1243
+ let routeFilePath = path7.resolve(
1244
+ ctx.reactRouterConfig.appDirectory,
1245
+ route.file
1246
+ );
1247
+ let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
1248
+ let code = fse.readFileSync(routeFilePath, "utf-8");
1249
+ return [
1250
+ `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
1251
+ ...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
1252
+ (exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
1253
+ ) : []
1254
+ ].filter(isNonNullable);
1255
+ }
1256
+ )
1257
+ ],
1258
+ output: {
1259
+ entryFileNames({ moduleIds }) {
1260
+ let routeChunkModuleId = moduleIds.find(isRouteChunkModuleId);
1261
+ let routeChunkName = routeChunkModuleId ? getRouteChunkNameFromModuleId(routeChunkModuleId) : null;
1262
+ let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
1263
+ return `assets/[name]${routeChunkSuffix}-[hash].js`;
1264
+ }
1265
+ }
1266
+ },
1267
+ outDir: getClientBuildDirectory(ctx.reactRouterConfig)
1268
+ }
1269
+ })
1270
+ };
1271
+ if (hasServerBundles(buildManifest)) {
1272
+ for (let [serverBundleId, routes2] of Object.entries(
1273
+ getRoutesByServerBundleId(buildManifest)
1274
+ )) {
1275
+ const serverBundleEnvironmentId = serverBundleId.replaceAll("-", "_");
1276
+ const environmentName = `${SSR_BUNDLE_PREFIX}${serverBundleEnvironmentId}`;
1277
+ environmentOptionsResolvers[environmentName] = ({ viteUserConfig }) => mergeEnvironmentOptions(
1278
+ getBaseServerOptions({ viteUserConfig }),
1279
+ {
1280
+ build: {
1281
+ outDir: getServerBuildDirectory(ctx, { serverBundleId }),
1282
+ rollupOptions: {
1283
+ input: `${virtual.serverBuild.id}?route-ids=${Object.keys(
1284
+ routes2
1285
+ ).join(",")}`
1286
+ }
1287
+ }
1288
+ },
1289
+ // Ensure server bundle environments extend the user's SSR
1290
+ // environment config if it exists
1291
+ viteUserConfig.environments?.ssr ?? {}
1292
+ );
1293
+ }
1294
+ } else {
1295
+ environmentOptionsResolvers.ssr = ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseServerOptions({ viteUserConfig }), {
1296
+ build: {
1297
+ outDir: getServerBuildDirectory(ctx),
1298
+ rollupOptions: {
1299
+ input: (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig.environments?.ssr?.build?.rollupOptions?.input : viteUserConfig.build?.rollupOptions?.input) ?? virtual.serverBuild.id
1300
+ }
1301
+ }
1302
+ });
1303
+ }
1304
+ return environmentOptionsResolvers;
1305
+ }
1306
+ function resolveEnvironmentsOptions(environmentResolvers, resolverOptions) {
1307
+ let environmentOptions = {};
1308
+ for (let [environmentName, resolver] of Object.entries(
1309
+ environmentResolvers
1310
+ )) {
1311
+ environmentOptions[environmentName] = resolver(resolverOptions);
1312
+ }
1313
+ return environmentOptions;
1314
+ }
1315
+ function isNonNullable(x) {
1316
+ return x != null;
1317
+ }
1318
+ 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;
955
1319
  var init_plugin = __esm({
956
1320
  "vite/plugin.ts"() {
957
1321
  "use strict";
@@ -962,8 +1326,10 @@ var init_plugin = __esm({
962
1326
  babel2 = __toESM(require("@babel/core"));
963
1327
  import_react_router2 = require("react-router");
964
1328
  import_es_module_lexer = require("es-module-lexer");
1329
+ import_pick3 = __toESM(require("lodash/pick"));
965
1330
  import_jsesc = __toESM(require("jsesc"));
966
1331
  import_picocolors4 = __toESM(require("picocolors"));
1332
+ import_kebabCase = __toESM(require("lodash/kebabCase"));
967
1333
  init_typegen();
968
1334
  init_invariant();
969
1335
  init_babel();
@@ -973,9 +1339,12 @@ var init_plugin = __esm({
973
1339
  init_resolve_file_url();
974
1340
  init_combine_urls();
975
1341
  init_remove_exports();
1342
+ init_route_chunks();
976
1343
  init_vite();
977
1344
  init_config();
978
1345
  init_with_props();
1346
+ BUILD_CLIENT_ROUTE_QUERY_STRING = "?__react-router-build-client-route";
1347
+ SSR_BUNDLE_PREFIX = "ssrBundle_";
979
1348
  virtualHmrRuntime = create("hmr-runtime");
980
1349
  virtualInjectHmrRuntime = create("inject-hmr-runtime");
981
1350
  virtual = {
@@ -983,11 +1352,12 @@ var init_plugin = __esm({
983
1352
  serverManifest: create("server-manifest"),
984
1353
  browserManifest: create("browser-manifest")
985
1354
  };
986
- getServerBuildDirectory = (ctx) => path7.join(
1355
+ getServerBuildDirectory = (ctx, { serverBundleId } = {}) => path7.join(
987
1356
  ctx.reactRouterConfig.buildDirectory,
988
1357
  "server",
989
- ...ctx.serverBundleBuildConfig ? [ctx.serverBundleBuildConfig.serverBundleId] : []
1358
+ ...serverBundleId ? [serverBundleId] : []
990
1359
  );
1360
+ getClientBuildDirectory = (reactRouterConfig) => path7.join(reactRouterConfig.buildDirectory, "client");
991
1361
  defaultEntriesDir = path7.resolve(
992
1362
  path7.dirname(require.resolve("@react-router/dev/package.json")),
993
1363
  "dist",
@@ -1025,144 +1395,83 @@ var build_exports = {};
1025
1395
  __export(build_exports, {
1026
1396
  build: () => build
1027
1397
  });
1028
- function getAddressableRoutes(routes2) {
1029
- let nonAddressableIds = /* @__PURE__ */ new Set();
1030
- for (let id in routes2) {
1031
- let route = routes2[id];
1032
- if (route.index) {
1033
- invariant(
1034
- route.parentId,
1035
- `Expected index route "${route.id}" to have "parentId" set`
1036
- );
1037
- nonAddressableIds.add(route.parentId);
1038
- }
1039
- if (typeof route.path !== "string" && !route.index) {
1040
- nonAddressableIds.add(id);
1041
- }
1398
+ async function build(root, viteBuildOptions) {
1399
+ await preloadVite();
1400
+ let vite2 = getVite();
1401
+ let configResult = await loadConfig({ rootDirectory: root });
1402
+ if (!configResult.ok) {
1403
+ throw new Error(configResult.error);
1042
1404
  }
1043
- return Object.values(routes2).filter(
1044
- (route) => !nonAddressableIds.has(route.id)
1045
- );
1046
- }
1047
- function getRouteBranch(routes2, routeId) {
1048
- let branch = [];
1049
- let currentRouteId = routeId;
1050
- while (currentRouteId) {
1051
- let route = routes2[currentRouteId];
1052
- invariant(route, `Missing route for ${currentRouteId}`);
1053
- branch.push(route);
1054
- currentRouteId = route.parentId;
1405
+ let config = configResult.value;
1406
+ let unstable_viteEnvironmentApi = config.future.unstable_viteEnvironmentApi;
1407
+ let viteMajor = parseInt(vite2.version.split(".")[0], 10);
1408
+ if (unstable_viteEnvironmentApi && viteMajor === 5) {
1409
+ throw new Error(
1410
+ "The future.unstable_viteEnvironmentApi option is not supported in Vite 5"
1411
+ );
1055
1412
  }
1056
- return branch.reverse();
1413
+ return await (unstable_viteEnvironmentApi ? viteAppBuild(root, viteBuildOptions) : viteBuild(root, viteBuildOptions));
1057
1414
  }
1058
- async function getServerBuilds(ctx) {
1059
- let { rootDirectory } = ctx;
1060
- const { routes: routes2, serverBuildFile, serverBundles, appDirectory } = ctx.reactRouterConfig;
1061
- let serverBuildDirectory = getServerBuildDirectory(ctx);
1062
- if (!serverBundles) {
1063
- return {
1064
- serverBuilds: [{ ssr: true }],
1065
- buildManifest: { routes: routes2 }
1066
- };
1067
- }
1068
- let { normalizePath } = await import("vite");
1069
- let resolvedAppDirectory = import_node_path2.default.resolve(rootDirectory, appDirectory);
1070
- let rootRelativeRoutes = Object.fromEntries(
1071
- Object.entries(routes2).map(([id, route]) => {
1072
- let filePath = import_node_path2.default.join(resolvedAppDirectory, route.file);
1073
- let rootRelativeFilePath = normalizePath(
1074
- import_node_path2.default.relative(rootDirectory, filePath)
1075
- );
1076
- return [id, { ...route, file: rootRelativeFilePath }];
1077
- })
1078
- );
1079
- let buildManifest = {
1080
- serverBundles: {},
1081
- routeIdToServerBundleId: {},
1082
- routes: rootRelativeRoutes
1083
- };
1084
- let serverBundleBuildConfigById = /* @__PURE__ */ new Map();
1085
- await Promise.all(
1086
- getAddressableRoutes(routes2).map(async (route) => {
1087
- let branch = getRouteBranch(routes2, route.id);
1088
- let serverBundleId = await serverBundles({
1089
- branch: branch.map(
1090
- (route2) => configRouteToBranchRoute({
1091
- ...route2,
1092
- // Ensure absolute paths are passed to the serverBundles function
1093
- file: import_node_path2.default.join(resolvedAppDirectory, route2.file)
1094
- })
1095
- )
1096
- });
1097
- if (typeof serverBundleId !== "string") {
1098
- throw new Error(`The "serverBundles" function must return a string`);
1099
- }
1100
- if (!/^[a-zA-Z0-9-_]+$/.test(serverBundleId)) {
1101
- throw new Error(
1102
- `The "serverBundles" function must only return strings containing alphanumeric characters, hyphens and underscores.`
1103
- );
1104
- }
1105
- buildManifest.routeIdToServerBundleId[route.id] = serverBundleId;
1106
- let relativeServerBundleDirectory = import_node_path2.default.relative(
1107
- rootDirectory,
1108
- import_node_path2.default.join(serverBuildDirectory, serverBundleId)
1109
- );
1110
- let serverBuildConfig = serverBundleBuildConfigById.get(serverBundleId);
1111
- if (!serverBuildConfig) {
1112
- buildManifest.serverBundles[serverBundleId] = {
1113
- id: serverBundleId,
1114
- file: normalizePath(
1115
- import_node_path2.default.join(relativeServerBundleDirectory, serverBuildFile)
1116
- )
1117
- };
1118
- serverBuildConfig = {
1119
- routes: {},
1120
- serverBundleId
1121
- };
1122
- serverBundleBuildConfigById.set(serverBundleId, serverBuildConfig);
1123
- }
1124
- for (let route2 of branch) {
1125
- serverBuildConfig.routes[route2.id] = route2;
1415
+ async function viteAppBuild(root, {
1416
+ assetsInlineLimit,
1417
+ clearScreen,
1418
+ config: configFile,
1419
+ emptyOutDir,
1420
+ force,
1421
+ logLevel,
1422
+ minify,
1423
+ mode,
1424
+ sourcemapClient,
1425
+ sourcemapServer
1426
+ }) {
1427
+ let vite2 = getVite();
1428
+ let builder = await vite2.createBuilder({
1429
+ root,
1430
+ mode,
1431
+ configFile,
1432
+ build: {
1433
+ assetsInlineLimit,
1434
+ emptyOutDir,
1435
+ minify
1436
+ },
1437
+ optimizeDeps: { force },
1438
+ clearScreen,
1439
+ logLevel,
1440
+ plugins: [
1441
+ {
1442
+ name: "react-router:cli-config",
1443
+ configEnvironment(name) {
1444
+ if (sourcemapClient && name === "client") {
1445
+ return {
1446
+ build: {
1447
+ sourcemap: sourcemapClient
1448
+ }
1449
+ };
1450
+ }
1451
+ if (sourcemapServer && name !== "client") {
1452
+ return {
1453
+ build: {
1454
+ sourcemap: sourcemapServer
1455
+ }
1456
+ };
1457
+ }
1458
+ },
1459
+ configResolved(config) {
1460
+ let hasReactRouterPlugin = config.plugins.find(
1461
+ (plugin2) => plugin2.name === "react-router"
1462
+ );
1463
+ if (!hasReactRouterPlugin) {
1464
+ throw new Error(
1465
+ "React Router Vite plugin not found in Vite config"
1466
+ );
1467
+ }
1468
+ }
1126
1469
  }
1127
- })
1128
- );
1129
- let serverBuilds = Array.from(serverBundleBuildConfigById.values()).map(
1130
- (serverBundleBuildConfig) => {
1131
- let serverBuild = {
1132
- ssr: true,
1133
- serverBundleBuildConfig
1134
- };
1135
- return serverBuild;
1136
- }
1137
- );
1138
- return {
1139
- serverBuilds,
1140
- buildManifest
1141
- };
1142
- }
1143
- async function cleanBuildDirectory(viteConfig, ctx) {
1144
- let buildDirectory = ctx.reactRouterConfig.buildDirectory;
1145
- let isWithinRoot = () => {
1146
- let relativePath = import_node_path2.default.relative(ctx.rootDirectory, buildDirectory);
1147
- return !relativePath.startsWith("..") && !import_node_path2.default.isAbsolute(relativePath);
1148
- };
1149
- if (viteConfig.build.emptyOutDir ?? isWithinRoot()) {
1150
- await import_fs_extra.default.remove(buildDirectory);
1151
- }
1152
- }
1153
- function getViteManifestPaths(ctx, serverBuilds) {
1154
- let buildRelative = (pathname) => import_node_path2.default.resolve(ctx.reactRouterConfig.buildDirectory, pathname);
1155
- let viteManifestPaths = [
1156
- "client/.vite/manifest.json",
1157
- ...serverBuilds.map(({ serverBundleBuildConfig }) => {
1158
- let serverBundleId = serverBundleBuildConfig?.serverBundleId;
1159
- let serverBundlePath = serverBundleId ? serverBundleId + "/" : "";
1160
- return `server/${serverBundlePath}.vite/manifest.json`;
1161
- })
1162
- ].map((srcPath) => buildRelative(srcPath));
1163
- return viteManifestPaths;
1470
+ ]
1471
+ });
1472
+ await builder.buildApp();
1164
1473
  }
1165
- async function build(root, {
1474
+ async function viteBuild(root, {
1166
1475
  assetsInlineLimit,
1167
1476
  clearScreen,
1168
1477
  config: configFile,
@@ -1174,21 +1483,36 @@ async function build(root, {
1174
1483
  sourcemapClient,
1175
1484
  sourcemapServer
1176
1485
  }) {
1177
- await preloadVite();
1178
- let viteConfig = await resolveViteConfig({ configFile, mode, root });
1179
- const ctx = await extractPluginContext(viteConfig);
1486
+ let viteUserConfig = {};
1487
+ let viteConfig = await resolveViteConfig({
1488
+ configFile,
1489
+ mode,
1490
+ root,
1491
+ plugins: [
1492
+ {
1493
+ name: "react-router:extract-vite-user-config",
1494
+ config(config) {
1495
+ viteUserConfig = config;
1496
+ }
1497
+ }
1498
+ ]
1499
+ });
1500
+ let ctx = await extractPluginContext(viteConfig);
1180
1501
  if (!ctx) {
1181
1502
  console.error(
1182
1503
  import_picocolors5.default.red("React Router Vite plugin not found in Vite config")
1183
1504
  );
1184
1505
  process.exit(1);
1185
1506
  }
1186
- let { reactRouterConfig } = ctx;
1187
- let vite2 = getVite();
1188
- async function viteBuild({
1189
- ssr,
1190
- serverBundleBuildConfig
1191
- }) {
1507
+ async function buildEnvironment(environmentName) {
1508
+ let vite2 = getVite();
1509
+ let ssr = environmentName !== "client";
1510
+ let resolveOptions = environmentOptionsResolvers[environmentName];
1511
+ invariant(resolveOptions);
1512
+ let environmentBuildContext = {
1513
+ name: environmentName,
1514
+ resolveOptions
1515
+ };
1192
1516
  await vite2.build({
1193
1517
  root,
1194
1518
  mode,
@@ -1203,43 +1527,41 @@ async function build(root, {
1203
1527
  optimizeDeps: { force },
1204
1528
  clearScreen,
1205
1529
  logLevel,
1206
- ...serverBundleBuildConfig ? { __reactRouterServerBundleBuildConfig: serverBundleBuildConfig } : {}
1530
+ ...{ __reactRouterEnvironmentBuildContext: environmentBuildContext }
1207
1531
  });
1208
1532
  }
1533
+ let { reactRouterConfig } = ctx;
1534
+ let buildManifest = await getBuildManifest(ctx);
1535
+ let environmentOptionsResolvers = await getEnvironmentOptionsResolvers(
1536
+ ctx,
1537
+ buildManifest,
1538
+ "build"
1539
+ );
1540
+ let environmentsOptions = resolveEnvironmentsOptions(
1541
+ environmentOptionsResolvers,
1542
+ { viteUserConfig }
1543
+ );
1209
1544
  await cleanBuildDirectory(viteConfig, ctx);
1210
- await viteBuild({ ssr: false });
1211
- let { serverBuilds, buildManifest } = await getServerBuilds(ctx);
1212
- await Promise.all(serverBuilds.map(viteBuild));
1213
- let viteManifestPaths = getViteManifestPaths(ctx, serverBuilds);
1214
- await Promise.all(
1215
- viteManifestPaths.map(async (viteManifestPath) => {
1216
- let manifestExists = await import_fs_extra.default.pathExists(viteManifestPath);
1217
- if (!manifestExists) return;
1218
- if (!ctx.viteManifestEnabled) {
1219
- await import_fs_extra.default.remove(viteManifestPath);
1220
- }
1221
- let viteDir = import_node_path2.default.dirname(viteManifestPath);
1222
- let viteDirFiles = await import_fs_extra.default.readdir(viteDir);
1223
- if (viteDirFiles.length === 0) {
1224
- await import_fs_extra.default.remove(viteDir);
1225
- }
1226
- })
1545
+ await buildEnvironment("client");
1546
+ let serverEnvironmentNames = getServerEnvironmentKeys(
1547
+ environmentOptionsResolvers,
1548
+ buildManifest
1227
1549
  );
1550
+ await Promise.all(serverEnvironmentNames.map(buildEnvironment));
1551
+ await cleanViteManifests(environmentsOptions, ctx);
1228
1552
  await reactRouterConfig.buildEnd?.({
1229
1553
  buildManifest,
1230
1554
  reactRouterConfig,
1231
1555
  viteConfig
1232
1556
  });
1233
1557
  }
1234
- var import_node_path2, import_fs_extra, import_picocolors5;
1558
+ var import_picocolors5;
1235
1559
  var init_build = __esm({
1236
1560
  "vite/build.ts"() {
1237
1561
  "use strict";
1238
- import_node_path2 = __toESM(require("path"));
1239
- import_fs_extra = __toESM(require("fs-extra"));
1240
1562
  import_picocolors5 = __toESM(require("picocolors"));
1241
- init_plugin();
1242
1563
  init_config();
1564
+ init_plugin();
1243
1565
  init_invariant();
1244
1566
  init_vite();
1245
1567
  }
@@ -1314,8 +1636,8 @@ var import_semver = __toESM(require("semver"));
1314
1636
  var import_picocolors8 = __toESM(require("picocolors"));
1315
1637
 
1316
1638
  // cli/commands.ts
1317
- var path9 = __toESM(require("path"));
1318
- var import_fs_extra2 = __toESM(require("fs-extra"));
1639
+ var path8 = __toESM(require("path"));
1640
+ var import_fs_extra = __toESM(require("fs-extra"));
1319
1641
  var import_package_json2 = __toESM(require("@npmcli/package-json"));
1320
1642
  var import_exit_hook = __toESM(require("exit-hook"));
1321
1643
  var import_picocolors7 = __toESM(require("picocolors"));
@@ -1468,14 +1790,14 @@ async function generateEntry(entry, reactRouterRoot, flags = {}) {
1468
1790
  console.error(import_picocolors7.default.red(`No default server entry detected.`));
1469
1791
  return;
1470
1792
  }
1471
- let defaultsDirectory = path9.resolve(
1472
- path9.dirname(require.resolve("@react-router/dev/package.json")),
1793
+ let defaultsDirectory = path8.resolve(
1794
+ path8.dirname(require.resolve("@react-router/dev/package.json")),
1473
1795
  "dist",
1474
1796
  "config",
1475
1797
  "defaults"
1476
1798
  );
1477
- let defaultEntryClient = path9.resolve(defaultsDirectory, "entry.client.tsx");
1478
- let defaultEntryServer = path9.resolve(
1799
+ let defaultEntryClient = path8.resolve(defaultsDirectory, "entry.client.tsx");
1800
+ let defaultEntryServer = path8.resolve(
1479
1801
  defaultsDirectory,
1480
1802
  `entry.server.node.tsx`
1481
1803
  );
@@ -1484,19 +1806,19 @@ async function generateEntry(entry, reactRouterRoot, flags = {}) {
1484
1806
  let useTypeScript = flags.typescript ?? true;
1485
1807
  let outputExtension = useTypeScript ? "tsx" : "jsx";
1486
1808
  let outputEntry = `${entry}.${outputExtension}`;
1487
- let outputFile2 = path9.resolve(appDirectory, outputEntry);
1809
+ let outputFile2 = path8.resolve(appDirectory, outputEntry);
1488
1810
  if (!useTypeScript) {
1489
1811
  let javascript = transpile(contents, {
1490
1812
  cwd: rootDirectory,
1491
1813
  filename: isServerEntry ? defaultEntryServer : defaultEntryClient
1492
1814
  });
1493
- await import_fs_extra2.default.writeFile(outputFile2, javascript, "utf-8");
1815
+ await import_fs_extra.default.writeFile(outputFile2, javascript, "utf-8");
1494
1816
  } else {
1495
- await import_fs_extra2.default.writeFile(outputFile2, contents, "utf-8");
1817
+ await import_fs_extra.default.writeFile(outputFile2, contents, "utf-8");
1496
1818
  }
1497
1819
  console.log(
1498
1820
  import_picocolors7.default.blue(
1499
- `Entry file ${entry} created at ${path9.relative(
1821
+ `Entry file ${entry} created at ${path8.relative(
1500
1822
  rootDirectory,
1501
1823
  outputFile2
1502
1824
  )}.`
@@ -1505,10 +1827,10 @@ async function generateEntry(entry, reactRouterRoot, flags = {}) {
1505
1827
  }
1506
1828
  async function checkForEntry(rootDirectory, appDirectory, entries2) {
1507
1829
  for (let entry of entries2) {
1508
- let entryPath = path9.resolve(appDirectory, entry);
1509
- let exists = await import_fs_extra2.default.pathExists(entryPath);
1830
+ let entryPath = path8.resolve(appDirectory, entry);
1831
+ let exists = await import_fs_extra.default.pathExists(entryPath);
1510
1832
  if (exists) {
1511
- let relative8 = path9.relative(rootDirectory, entryPath);
1833
+ let relative8 = path8.relative(rootDirectory, entryPath);
1512
1834
  console.error(import_picocolors7.default.red(`Entry file ${relative8} already exists.`));
1513
1835
  return process.exit(1);
1514
1836
  }
@@ -1516,12 +1838,12 @@ async function checkForEntry(rootDirectory, appDirectory, entries2) {
1516
1838
  }
1517
1839
  async function createServerEntry(rootDirectory, appDirectory, inputFile) {
1518
1840
  await checkForEntry(rootDirectory, appDirectory, serverEntries);
1519
- let contents = await import_fs_extra2.default.readFile(inputFile, "utf-8");
1841
+ let contents = await import_fs_extra.default.readFile(inputFile, "utf-8");
1520
1842
  return contents;
1521
1843
  }
1522
1844
  async function createClientEntry(rootDirectory, appDirectory, inputFile) {
1523
1845
  await checkForEntry(rootDirectory, appDirectory, clientEntries);
1524
- let contents = await import_fs_extra2.default.readFile(inputFile, "utf-8");
1846
+ let contents = await import_fs_extra.default.readFile(inputFile, "utf-8");
1525
1847
  return contents;
1526
1848
  }
1527
1849
  async function typegen(root, flags) {