@react-router/dev 0.0.0-experimental-345f1da12 → 0.0.0-experimental-df6bc686c

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-345f1da12
2
+ * @react-router/dev v0.0.0-experimental-df6bc686c
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -57,8 +57,7 @@ var import_picocolors3 = __toESM(require("picocolors"));
57
57
 
58
58
  // typegen/index.ts
59
59
  var import_node_fs2 = __toESM(require("fs"));
60
- var import_dedent2 = __toESM(require("dedent"));
61
- var Path3 = __toESM(require("pathe"));
60
+ var Path4 = __toESM(require("pathe"));
62
61
  var import_picocolors2 = __toESM(require("picocolors"));
63
62
 
64
63
  // config/config.ts
@@ -372,6 +371,7 @@ async function resolveConfig({
372
371
  basename: basename2,
373
372
  buildDirectory: userBuildDirectory,
374
373
  buildEnd,
374
+ future: userFuture,
375
375
  prerender,
376
376
  serverBuildFile,
377
377
  serverBundles,
@@ -444,7 +444,8 @@ async function resolveConfig({
444
444
  );
445
445
  }
446
446
  let future = {
447
- unstable_optimizeDeps: reactRouterUserConfig.future?.unstable_optimizeDeps ?? false
447
+ unstable_optimizeDeps: reactRouterUserConfig.future?.unstable_optimizeDeps ?? false,
448
+ unstable_splitRouteModules: userFuture?.unstable_splitRouteModules ?? false
448
449
  };
449
450
  let reactRouterConfig = deepFreeze({
450
451
  appDirectory,
@@ -625,54 +626,125 @@ function findEntry(dir, basename2, options) {
625
626
 
626
627
  // typegen/generate.ts
627
628
  var import_dedent = __toESM(require("dedent"));
628
- function generate(route) {
629
+ var Path3 = __toESM(require("pathe"));
630
+ var Pathe2 = __toESM(require("pathe/utils"));
631
+
632
+ // typegen/paths.ts
633
+ var Path2 = __toESM(require("pathe"));
634
+ var Pathe = __toESM(require("pathe/utils"));
635
+ function getTypesDir(ctx) {
636
+ return Path2.join(ctx.rootDirectory, ".react-router/types");
637
+ }
638
+ function getTypesPath(ctx, route) {
639
+ return Path2.join(
640
+ getTypesDir(ctx),
641
+ Path2.relative(ctx.rootDirectory, ctx.config.appDirectory),
642
+ Path2.dirname(route.file),
643
+ "+types/" + Pathe.filename(route.file) + ".ts"
644
+ );
645
+ }
646
+
647
+ // typegen/generate.ts
648
+ function generate(ctx, route) {
649
+ const lineage = getRouteLineage(ctx.config.routes, route);
650
+ const urlpath = lineage.map((route2) => route2.path).join("/");
651
+ const typesPath = getTypesPath(ctx, route);
652
+ const parents = lineage.slice(0, -1);
653
+ const parentTypeImports = parents.map((parent, i) => {
654
+ const rel = Path3.relative(
655
+ Path3.dirname(typesPath),
656
+ getTypesPath(ctx, parent)
657
+ );
658
+ const indent = i === 0 ? "" : " ".repeat(2);
659
+ let source = noExtension(rel);
660
+ if (!source.startsWith("../")) source = "./" + source;
661
+ return `${indent}import type { Info as Parent${i} } from "${source}.js"`;
662
+ }).join("\n");
629
663
  return import_dedent.default`
630
664
  // React Router generated types for route:
631
665
  // ${route.file}
632
666
 
633
- import type { RouteExports, Routes } from "react-router/types";
667
+ import type * as T from "react-router/route-module"
668
+
669
+ ${parentTypeImports}
634
670
 
635
- type RouteId = "${route.id}"
636
- export type Info = Routes[RouteId];
671
+ type Module = typeof import("../${Pathe2.filename(route.file)}.js")
637
672
 
638
- type Exports = RouteExports[RouteId];
673
+ export type Info = {
674
+ parents: [${parents.map((_, i) => `Parent${i}`).join(", ")}],
675
+ id: "${route.id}"
676
+ file: "${route.file}"
677
+ path: "${route.path}"
678
+ params: {${formatParamProperties(
679
+ urlpath
680
+ )}} & { [key: string]: string | undefined }
681
+ module: Module
682
+ loaderData: T.CreateLoaderData<Module>
683
+ actionData: T.CreateActionData<Module>
684
+ }
639
685
 
640
686
  export namespace Route {
641
- export type LinkDescriptors = Exports["links"]["return"];
642
- export type LinksFunction = () => LinkDescriptors;
687
+ export type LinkDescriptors = T.LinkDescriptors
688
+ export type LinksFunction = () => LinkDescriptors
643
689
 
644
- export type MetaArgs = Exports["meta"]["args"];
645
- export type MetaDescriptors = Exports["meta"]["return"];
646
- export type MetaFunction = (args: MetaArgs) => MetaDescriptors;
690
+ export type MetaArgs = T.CreateMetaArgs<Info>
691
+ export type MetaDescriptors = T.MetaDescriptors
692
+ export type MetaFunction = (args: MetaArgs) => MetaDescriptors
647
693
 
648
- export type HeadersArgs = Exports["headers"]["args"];
649
- export type HeadersFunction = (args: HeadersArgs) => Headers | HeadersInit;
694
+ export type HeadersArgs = T.HeadersArgs
695
+ export type HeadersFunction = (args: HeadersArgs) => Headers | HeadersInit
650
696
 
651
- export type LoaderArgs = Exports["loader"]["args"];
652
- export type ClientLoaderArgs = Exports["clientLoader"]["args"];
653
- export type ActionArgs = Exports["action"]["args"];
654
- export type ClientActionArgs = Exports["clientAction"]["args"];
697
+ export type LoaderArgs = T.CreateServerLoaderArgs<Info>
698
+ export type ClientLoaderArgs = T.CreateClientLoaderArgs<Info>
699
+ export type ActionArgs = T.CreateServerActionArgs<Info>
700
+ export type ClientActionArgs = T.CreateClientActionArgs<Info>
655
701
 
656
- export type HydrateFallbackProps = Exports["HydrateFallback"]["args"];
657
- export type ComponentProps = Exports["default"]["args"];
658
- export type ErrorBoundaryProps = Exports["ErrorBoundary"]["args"];
702
+ export type HydrateFallbackProps = T.CreateHydrateFallbackProps<Info>
703
+ export type ComponentProps = T.CreateComponentProps<Info>
704
+ export type ErrorBoundaryProps = T.CreateErrorBoundaryProps<Info>
659
705
  }
660
706
  `;
661
707
  }
662
-
663
- // typegen/paths.ts
664
- var Path2 = __toESM(require("pathe"));
665
- var Pathe = __toESM(require("pathe/utils"));
666
- function getTypesDir(ctx) {
667
- return Path2.join(ctx.rootDirectory, ".react-router/types");
708
+ var noExtension = (path7) => Path3.join(Path3.dirname(path7), Pathe2.filename(path7));
709
+ function getRouteLineage(routes, route) {
710
+ const result = [];
711
+ while (route) {
712
+ result.push(route);
713
+ if (!route.parentId) break;
714
+ route = routes[route.parentId];
715
+ }
716
+ result.reverse();
717
+ return result;
668
718
  }
669
- function getTypesPath(ctx, route) {
670
- return Path2.join(
671
- getTypesDir(ctx),
672
- Path2.relative(ctx.rootDirectory, ctx.config.appDirectory),
673
- Path2.dirname(route.file),
674
- "+types/" + Pathe.filename(route.file) + ".ts"
675
- );
719
+ function formatParamProperties(urlpath) {
720
+ const params = parseParams(urlpath);
721
+ const properties = Object.entries(params).map(([name, values]) => {
722
+ if (values.length === 1) {
723
+ const isOptional = values[0];
724
+ return isOptional ? `"${name}"?: string` : `"${name}": string`;
725
+ }
726
+ const items = values.map(
727
+ (isOptional) => isOptional ? "string | undefined" : "string"
728
+ );
729
+ return `"${name}": [${items.join(", ")}]`;
730
+ });
731
+ return properties.join("; ");
732
+ }
733
+ function parseParams(urlpath) {
734
+ const result = {};
735
+ let segments = urlpath.split("/");
736
+ segments.forEach((segment) => {
737
+ const match = segment.match(/^:([\w-]+)(\?)?/);
738
+ if (!match) return;
739
+ const param = match[1];
740
+ const isOptional = match[2] !== void 0;
741
+ result[param] ??= [];
742
+ result[param].push(isOptional);
743
+ return;
744
+ });
745
+ const hasSplat = segments.at(-1) === "*";
746
+ if (hasSplat) result["*"] = [false];
747
+ return result;
676
748
  }
677
749
 
678
750
  // typegen/index.ts
@@ -714,93 +786,16 @@ async function createContext2({
714
786
  config
715
787
  };
716
788
  }
717
- function asJS(path7) {
718
- return path7.replace(/\.(js|ts)x?$/, ".js");
719
- }
720
- function formatRoute({ id, path: path7, file, parentId }) {
721
- return [
722
- `"${id}": {`,
723
- ` parentId: ${JSON.stringify(parentId)}`,
724
- ` path: ${JSON.stringify(path7)}`,
725
- ` module: typeof import("./app/${asJS(file)}")`,
726
- `}`
727
- ].map((line) => ` ${line}`).join("\n");
728
- }
729
789
  async function writeAll(ctx) {
730
- let routes = Object.values(ctx.config.routes);
731
- let pathsToParams = /* @__PURE__ */ new Map();
732
- for (let route of routes) {
733
- if (route.path === void 0) continue;
734
- let lineage = getRouteLineage(ctx.config.routes, route);
735
- let path7 = lineage.filter((route2) => route2.path !== void 0).map((route2) => route2.path).join("/");
736
- if (path7 === "") path7 = "/";
737
- pathsToParams.set(path7, parseParams(path7));
738
- }
739
- let formattedPaths = `type Paths = {`;
740
- for (let [path7, params] of pathsToParams.entries()) {
741
- let formattedParams = Object.entries(params).map(
742
- ([param, required]) => `"${param}"${required ? "" : "?"}: string`
743
- );
744
- let formattedEntry = `"${path7}": {${formattedParams.join(",")}},
745
- `;
746
- formattedPaths += formattedEntry;
747
- }
748
- formattedPaths += `}`;
749
790
  const typegenDir = getTypesDir(ctx);
750
791
  import_node_fs2.default.rmSync(typegenDir, { recursive: true, force: true });
751
- const newTypes = Path3.join(typegenDir, "routes.ts");
752
- import_node_fs2.default.mkdirSync(Path3.dirname(newTypes), { recursive: true });
753
- import_node_fs2.default.writeFileSync(
754
- newTypes,
755
- formattedPaths + `
756
-
757
- type Routes = {
758
- ${routes.map(formatRoute).join("\n")}
759
- }
760
-
761
- ` + import_dedent2.default`
762
- declare module "react-router/types" {
763
- interface Register {
764
- paths: Paths
765
- routes: Routes
766
- }
767
- }
768
-
769
- export {}
770
- `
771
- );
772
792
  Object.values(ctx.config.routes).forEach((route) => {
773
793
  const typesPath = getTypesPath(ctx, route);
774
- const content = generate(route);
775
- import_node_fs2.default.mkdirSync(Path3.dirname(typesPath), { recursive: true });
794
+ const content = generate(ctx, route);
795
+ import_node_fs2.default.mkdirSync(Path4.dirname(typesPath), { recursive: true });
776
796
  import_node_fs2.default.writeFileSync(typesPath, content);
777
797
  });
778
798
  }
779
- function getRouteLineage(routes, route) {
780
- const result = [];
781
- while (route) {
782
- result.push(route);
783
- if (!route.parentId) break;
784
- route = routes[route.parentId];
785
- }
786
- result.reverse();
787
- return result;
788
- }
789
- function parseParams(urlpath) {
790
- const result = {};
791
- let segments = urlpath.split("/");
792
- segments.forEach((segment) => {
793
- const match = segment.match(/^:([\w-]+)(\?)?/);
794
- if (!match) return;
795
- const param = match[1];
796
- const isRequired = match[2] === void 0;
797
- result[param] ||= isRequired;
798
- return;
799
- });
800
- const hasSplat = segments.at(-1) === "*";
801
- if (hasSplat) result["*"] = true;
802
- return result;
803
- }
804
799
 
805
800
  // vite/babel.ts
806
801
  var import_parser = require("@babel/parser");
@@ -1166,8 +1161,609 @@ function invalidDestructureError(name) {
1166
1161
  return new Error(`Cannot remove destructured export "${name}"`);
1167
1162
  }
1168
1163
 
1164
+ // vite/cache.ts
1165
+ function getOrSetFromCache(cache, key, version, getValue) {
1166
+ if (!cache) {
1167
+ return getValue();
1168
+ }
1169
+ let entry = cache.get(key);
1170
+ if (entry?.version === version) {
1171
+ return entry.value;
1172
+ }
1173
+ let value = getValue();
1174
+ let newEntry = { value, version };
1175
+ cache.set(key, newEntry);
1176
+ return value;
1177
+ }
1178
+
1179
+ // vite/route-chunks.ts
1180
+ function codeToAst(code, cache, cacheKey) {
1181
+ return structuredClone(
1182
+ getOrSetFromCache(
1183
+ cache,
1184
+ `${cacheKey}::codeToAst`,
1185
+ code,
1186
+ () => (0, import_parser.parse)(code, { sourceType: "module" })
1187
+ )
1188
+ );
1189
+ }
1190
+ function assertNodePath(path7) {
1191
+ invariant(
1192
+ path7 && !Array.isArray(path7),
1193
+ `Expected a Path, but got ${Array.isArray(path7) ? "an array" : path7}`
1194
+ );
1195
+ }
1196
+ function assertNodePathIsStatement(path7) {
1197
+ invariant(
1198
+ path7 && !Array.isArray(path7) && t.isStatement(path7.node),
1199
+ `Expected a Statement path, but got ${Array.isArray(path7) ? "an array" : path7?.node?.type}`
1200
+ );
1201
+ }
1202
+ function assertNodePathIsVariableDeclarator(path7) {
1203
+ invariant(
1204
+ path7 && !Array.isArray(path7) && t.isVariableDeclarator(path7.node),
1205
+ `Expected an Identifier path, but got ${Array.isArray(path7) ? "an array" : path7?.node?.type}`
1206
+ );
1207
+ }
1208
+ function assertNodePathIsPattern(path7) {
1209
+ invariant(
1210
+ path7 && !Array.isArray(path7) && t.isPattern(path7.node),
1211
+ `Expected a Pattern path, but got ${Array.isArray(path7) ? "an array" : path7?.node?.type}`
1212
+ );
1213
+ }
1214
+ function getExportDependencies(code, cache, cacheKey) {
1215
+ return getOrSetFromCache(
1216
+ cache,
1217
+ `${cacheKey}::getExportDependencies`,
1218
+ code,
1219
+ () => {
1220
+ let exportDependencies = /* @__PURE__ */ new Map();
1221
+ let ast = codeToAst(code, cache, cacheKey);
1222
+ function handleExport(exportName, exportPath, identifiersPath = exportPath) {
1223
+ let identifiers = getDependentIdentifiersForPath(identifiersPath);
1224
+ let topLevelStatements = /* @__PURE__ */ new Set([
1225
+ exportPath.node,
1226
+ ...getTopLevelStatementsForPaths(identifiers)
1227
+ ]);
1228
+ let topLevelNonModuleStatements = new Set(
1229
+ Array.from(topLevelStatements).filter(
1230
+ (statement) => !t.isImportDeclaration(statement) && !t.isExportDeclaration(statement)
1231
+ )
1232
+ );
1233
+ let importedIdentifierNames = /* @__PURE__ */ new Set();
1234
+ for (let identifier of identifiers) {
1235
+ if (identifier.parentPath.parentPath?.isImportDeclaration()) {
1236
+ importedIdentifierNames.add(identifier.node.name);
1237
+ }
1238
+ }
1239
+ let exportedVariableDeclarators = /* @__PURE__ */ new Set();
1240
+ for (let identifier of identifiers) {
1241
+ if (identifier.parentPath.isVariableDeclarator() && identifier.parentPath.parentPath.parentPath?.isExportNamedDeclaration()) {
1242
+ exportedVariableDeclarators.add(identifier.parentPath.node);
1243
+ continue;
1244
+ }
1245
+ let isWithinExportNamedDeclaration = Boolean(
1246
+ identifier.findParent((path7) => path7.isExportNamedDeclaration())
1247
+ );
1248
+ if (isWithinExportNamedDeclaration) {
1249
+ let currentPath = identifier;
1250
+ while (currentPath) {
1251
+ if (
1252
+ // Check the identifier is within a variable declaration, and if
1253
+ // so, ensure we're on the left-hand side of the expression
1254
+ // since these identifiers are what make up the export names,
1255
+ // e.g. export const { foo } = { foo: bar }; should pick up
1256
+ // `foo` but not `bar`.
1257
+ currentPath.parentPath?.isVariableDeclarator() && currentPath.parentKey === "id"
1258
+ ) {
1259
+ exportedVariableDeclarators.add(currentPath.parentPath.node);
1260
+ break;
1261
+ }
1262
+ currentPath = currentPath.parentPath;
1263
+ }
1264
+ }
1265
+ }
1266
+ let dependencies = {
1267
+ topLevelStatements,
1268
+ topLevelNonModuleStatements,
1269
+ importedIdentifierNames,
1270
+ exportedVariableDeclarators
1271
+ };
1272
+ exportDependencies.set(exportName, dependencies);
1273
+ }
1274
+ traverse(ast, {
1275
+ ExportDeclaration(exportPath) {
1276
+ let { node } = exportPath;
1277
+ if (t.isExportAllDeclaration(node)) {
1278
+ return;
1279
+ }
1280
+ if (t.isExportDefaultDeclaration(node)) {
1281
+ handleExport("default", exportPath);
1282
+ return;
1283
+ }
1284
+ let { declaration } = node;
1285
+ if (t.isVariableDeclaration(declaration)) {
1286
+ let { declarations } = declaration;
1287
+ for (let i = 0; i < declarations.length; i++) {
1288
+ let declarator = declarations[i];
1289
+ if (t.isIdentifier(declarator.id)) {
1290
+ let declaratorPath = exportPath.get(
1291
+ `declaration.declarations.${i}`
1292
+ );
1293
+ assertNodePathIsVariableDeclarator(declaratorPath);
1294
+ handleExport(declarator.id.name, exportPath, declaratorPath);
1295
+ continue;
1296
+ }
1297
+ if (t.isPattern(declarator.id)) {
1298
+ let exportedPatternPath = exportPath.get(
1299
+ `declaration.declarations.${i}.id`
1300
+ );
1301
+ assertNodePathIsPattern(exportedPatternPath);
1302
+ let identifiers = getIdentifiersForPatternPath(exportedPatternPath);
1303
+ for (let identifier of identifiers) {
1304
+ handleExport(identifier.node.name, exportPath, identifier);
1305
+ }
1306
+ }
1307
+ }
1308
+ return;
1309
+ }
1310
+ if (t.isFunctionDeclaration(declaration) || t.isClassDeclaration(declaration)) {
1311
+ invariant(
1312
+ declaration.id,
1313
+ "Expected exported function or class declaration to have a name when not the default export"
1314
+ );
1315
+ handleExport(declaration.id.name, exportPath);
1316
+ return;
1317
+ }
1318
+ if (t.isExportNamedDeclaration(node)) {
1319
+ for (let specifier of node.specifiers) {
1320
+ if (t.isIdentifier(specifier.exported)) {
1321
+ let name = specifier.exported.name;
1322
+ let specifierPath = exportPath.get("specifiers").find((path7) => path7.node === specifier);
1323
+ invariant(
1324
+ specifierPath,
1325
+ `Expected to find specifier path for ${name}`
1326
+ );
1327
+ handleExport(name, exportPath, specifierPath);
1328
+ }
1329
+ }
1330
+ return;
1331
+ }
1332
+ throw new Error(`Unknown export node type: ${node.type}`);
1333
+ }
1334
+ });
1335
+ return exportDependencies;
1336
+ }
1337
+ );
1338
+ }
1339
+ function getDependentIdentifiersForPath(path7, state) {
1340
+ let { visited, identifiers } = state ?? {
1341
+ visited: /* @__PURE__ */ new Set(),
1342
+ identifiers: /* @__PURE__ */ new Set()
1343
+ };
1344
+ if (visited.has(path7)) {
1345
+ return identifiers;
1346
+ }
1347
+ visited.add(path7);
1348
+ path7.traverse({
1349
+ Identifier(path8) {
1350
+ if (identifiers.has(path8)) {
1351
+ return;
1352
+ }
1353
+ identifiers.add(path8);
1354
+ let binding = path8.scope.getBinding(path8.node.name);
1355
+ if (!binding) {
1356
+ return;
1357
+ }
1358
+ getDependentIdentifiersForPath(binding.path, { visited, identifiers });
1359
+ for (let reference of binding.referencePaths) {
1360
+ if (reference.isExportNamedDeclaration()) {
1361
+ continue;
1362
+ }
1363
+ getDependentIdentifiersForPath(reference, {
1364
+ visited,
1365
+ identifiers
1366
+ });
1367
+ }
1368
+ for (let constantViolation of binding.constantViolations) {
1369
+ getDependentIdentifiersForPath(constantViolation, {
1370
+ visited,
1371
+ identifiers
1372
+ });
1373
+ }
1374
+ }
1375
+ });
1376
+ let topLevelStatement = getTopLevelStatementPathForPath(path7);
1377
+ let withinImportStatement = topLevelStatement.isImportDeclaration();
1378
+ let withinExportStatement = topLevelStatement.isExportDeclaration();
1379
+ if (!withinImportStatement && !withinExportStatement) {
1380
+ getDependentIdentifiersForPath(topLevelStatement, {
1381
+ visited,
1382
+ identifiers
1383
+ });
1384
+ }
1385
+ if (withinExportStatement && path7.isIdentifier() && (t.isPattern(path7.parentPath.node) || // [foo]
1386
+ t.isPattern(path7.parentPath.parentPath?.node))) {
1387
+ let variableDeclarator = path7.findParent((p) => p.isVariableDeclarator());
1388
+ assertNodePath(variableDeclarator);
1389
+ getDependentIdentifiersForPath(variableDeclarator, {
1390
+ visited,
1391
+ identifiers
1392
+ });
1393
+ }
1394
+ return identifiers;
1395
+ }
1396
+ function getTopLevelStatementPathForPath(path7) {
1397
+ let ancestry = path7.getAncestry();
1398
+ let topLevelStatement = ancestry[ancestry.length - 2];
1399
+ assertNodePathIsStatement(topLevelStatement);
1400
+ return topLevelStatement;
1401
+ }
1402
+ function getTopLevelStatementsForPaths(paths) {
1403
+ let topLevelStatements = /* @__PURE__ */ new Set();
1404
+ for (let path7 of paths) {
1405
+ let topLevelStatement = getTopLevelStatementPathForPath(path7);
1406
+ topLevelStatements.add(topLevelStatement.node);
1407
+ }
1408
+ return topLevelStatements;
1409
+ }
1410
+ function getIdentifiersForPatternPath(patternPath, identifiers = /* @__PURE__ */ new Set()) {
1411
+ function walk(currentPath) {
1412
+ if (currentPath.isIdentifier()) {
1413
+ identifiers.add(currentPath);
1414
+ return;
1415
+ }
1416
+ if (currentPath.isObjectPattern()) {
1417
+ let { properties } = currentPath.node;
1418
+ for (let i = 0; i < properties.length; i++) {
1419
+ const property = properties[i];
1420
+ if (t.isObjectProperty(property)) {
1421
+ let valuePath = currentPath.get(`properties.${i}.value`);
1422
+ assertNodePath(valuePath);
1423
+ walk(valuePath);
1424
+ } else if (t.isRestElement(property)) {
1425
+ let argumentPath = currentPath.get(`properties.${i}.argument`);
1426
+ assertNodePath(argumentPath);
1427
+ walk(argumentPath);
1428
+ }
1429
+ }
1430
+ } else if (currentPath.isArrayPattern()) {
1431
+ let { elements } = currentPath.node;
1432
+ for (let i = 0; i < elements.length; i++) {
1433
+ const element = elements[i];
1434
+ if (element) {
1435
+ let elementPath = currentPath.get(`elements.${i}`);
1436
+ assertNodePath(elementPath);
1437
+ walk(elementPath);
1438
+ }
1439
+ }
1440
+ } else if (currentPath.isRestElement()) {
1441
+ let argumentPath = currentPath.get("argument");
1442
+ assertNodePath(argumentPath);
1443
+ walk(argumentPath);
1444
+ }
1445
+ }
1446
+ walk(patternPath);
1447
+ return identifiers;
1448
+ }
1449
+ var getExportedName = (exported) => {
1450
+ return t.isIdentifier(exported) ? exported.name : exported.value;
1451
+ };
1452
+ function setsIntersect(set1, set2) {
1453
+ let smallerSet = set1;
1454
+ let largerSet = set2;
1455
+ if (set1.size > set2.size) {
1456
+ smallerSet = set2;
1457
+ largerSet = set1;
1458
+ }
1459
+ for (let element of smallerSet) {
1460
+ if (largerSet.has(element)) {
1461
+ return true;
1462
+ }
1463
+ }
1464
+ return false;
1465
+ }
1466
+ function hasChunkableExport(code, exportName, cache, cacheKey) {
1467
+ return getOrSetFromCache(
1468
+ cache,
1469
+ `${cacheKey}::hasChunkableExport::${exportName}`,
1470
+ code,
1471
+ () => {
1472
+ let exportDependencies = getExportDependencies(code, cache, cacheKey);
1473
+ let dependencies = exportDependencies.get(exportName);
1474
+ if (!dependencies) {
1475
+ return false;
1476
+ }
1477
+ for (let [currentExportName, currentDependencies] of exportDependencies) {
1478
+ if (currentExportName === exportName) {
1479
+ continue;
1480
+ }
1481
+ if (setsIntersect(
1482
+ currentDependencies.topLevelNonModuleStatements,
1483
+ dependencies.topLevelNonModuleStatements
1484
+ )) {
1485
+ return false;
1486
+ }
1487
+ }
1488
+ if (dependencies.exportedVariableDeclarators.size > 1) {
1489
+ return false;
1490
+ }
1491
+ if (dependencies.exportedVariableDeclarators.size > 0) {
1492
+ for (let [
1493
+ currentExportName,
1494
+ currentDependencies
1495
+ ] of exportDependencies) {
1496
+ if (currentExportName === exportName) {
1497
+ continue;
1498
+ }
1499
+ if (setsIntersect(
1500
+ currentDependencies.exportedVariableDeclarators,
1501
+ dependencies.exportedVariableDeclarators
1502
+ )) {
1503
+ return false;
1504
+ }
1505
+ }
1506
+ }
1507
+ return true;
1508
+ }
1509
+ );
1510
+ }
1511
+ function getChunkedExport(code, exportName, generateOptions = {}, cache, cacheKey) {
1512
+ return getOrSetFromCache(
1513
+ cache,
1514
+ `${cacheKey}::getChunkedExport::${exportName}::${JSON.stringify(
1515
+ generateOptions
1516
+ )}`,
1517
+ code,
1518
+ () => {
1519
+ if (!hasChunkableExport(code, exportName, cache, cacheKey)) {
1520
+ return void 0;
1521
+ }
1522
+ let exportDependencies = getExportDependencies(code, cache, cacheKey);
1523
+ let dependencies = exportDependencies.get(exportName);
1524
+ invariant(dependencies, "Expected export to have dependencies");
1525
+ let topLevelStatementsArray = Array.from(dependencies.topLevelStatements);
1526
+ let exportedVariableDeclaratorsArray = Array.from(
1527
+ dependencies.exportedVariableDeclarators
1528
+ );
1529
+ let ast = codeToAst(code, cache, cacheKey);
1530
+ ast.program.body = ast.program.body.filter(
1531
+ (node) => topLevelStatementsArray.some(
1532
+ (statement) => t.isNodesEquivalent(node, statement)
1533
+ )
1534
+ ).map((node) => {
1535
+ if (!t.isImportDeclaration(node)) {
1536
+ return node;
1537
+ }
1538
+ if (dependencies.importedIdentifierNames.size === 0) {
1539
+ return null;
1540
+ }
1541
+ node.specifiers = node.specifiers.filter(
1542
+ (specifier) => dependencies.importedIdentifierNames.has(specifier.local.name)
1543
+ );
1544
+ invariant(
1545
+ node.specifiers.length > 0,
1546
+ "Expected import statement to have used specifiers"
1547
+ );
1548
+ return node;
1549
+ }).map((node) => {
1550
+ if (!t.isExportDeclaration(node)) {
1551
+ return node;
1552
+ }
1553
+ if (t.isExportAllDeclaration(node)) {
1554
+ return null;
1555
+ }
1556
+ if (t.isExportDefaultDeclaration(node)) {
1557
+ return exportName === "default" ? node : null;
1558
+ }
1559
+ let { declaration } = node;
1560
+ if (t.isVariableDeclaration(declaration)) {
1561
+ declaration.declarations = declaration.declarations.filter(
1562
+ (node2) => exportedVariableDeclaratorsArray.some(
1563
+ (declarator) => t.isNodesEquivalent(node2, declarator)
1564
+ )
1565
+ );
1566
+ if (declaration.declarations.length === 0) {
1567
+ return null;
1568
+ }
1569
+ return node;
1570
+ }
1571
+ if (t.isFunctionDeclaration(node.declaration) || t.isClassDeclaration(node.declaration)) {
1572
+ return node.declaration.id?.name === exportName ? node : null;
1573
+ }
1574
+ if (t.isExportNamedDeclaration(node)) {
1575
+ if (node.specifiers.length === 0) {
1576
+ return null;
1577
+ }
1578
+ node.specifiers = node.specifiers.filter(
1579
+ (specifier) => getExportedName(specifier.exported) === exportName
1580
+ );
1581
+ if (node.specifiers.length === 0) {
1582
+ return null;
1583
+ }
1584
+ return node;
1585
+ }
1586
+ throw new Error(`Unknown export node type: ${node.type}`);
1587
+ }).filter((node) => node !== null);
1588
+ return generate2(ast, generateOptions);
1589
+ }
1590
+ );
1591
+ }
1592
+ function omitChunkedExports(code, exportNames, generateOptions = {}, cache, cacheKey) {
1593
+ return getOrSetFromCache(
1594
+ cache,
1595
+ `${cacheKey}::omitChunkedExports::${exportNames.join(
1596
+ ","
1597
+ )}::${JSON.stringify(generateOptions)}`,
1598
+ code,
1599
+ () => {
1600
+ const isChunkable = (exportName) => hasChunkableExport(code, exportName, cache, cacheKey);
1601
+ const isOmitted = (exportName) => exportNames.includes(exportName) && isChunkable(exportName);
1602
+ const isRetained = (exportName) => !isOmitted(exportName);
1603
+ let exportDependencies = getExportDependencies(code, cache, cacheKey);
1604
+ let allExportNames = Array.from(exportDependencies.keys());
1605
+ let omittedExportNames = allExportNames.filter(isOmitted);
1606
+ let retainedExportNames = allExportNames.filter(isRetained);
1607
+ let omittedStatements = /* @__PURE__ */ new Set();
1608
+ let omittedExportedVariableDeclarators = /* @__PURE__ */ new Set();
1609
+ for (let omittedExportName of omittedExportNames) {
1610
+ let dependencies = exportDependencies.get(omittedExportName);
1611
+ invariant(
1612
+ dependencies,
1613
+ `Expected dependencies for ${omittedExportName}`
1614
+ );
1615
+ for (let statement of dependencies.topLevelNonModuleStatements) {
1616
+ omittedStatements.add(statement);
1617
+ }
1618
+ for (let declarator of dependencies.exportedVariableDeclarators) {
1619
+ omittedExportedVariableDeclarators.add(declarator);
1620
+ }
1621
+ }
1622
+ let ast = codeToAst(code, cache, cacheKey);
1623
+ let omittedStatementsArray = Array.from(omittedStatements);
1624
+ let omittedExportedVariableDeclaratorsArray = Array.from(
1625
+ omittedExportedVariableDeclarators
1626
+ );
1627
+ ast.program.body = ast.program.body.filter(
1628
+ (node) => omittedStatementsArray.every(
1629
+ (statement) => !t.isNodesEquivalent(node, statement)
1630
+ )
1631
+ ).map((node) => {
1632
+ if (!t.isImportDeclaration(node)) {
1633
+ return node;
1634
+ }
1635
+ if (node.specifiers.length === 0) {
1636
+ return node;
1637
+ }
1638
+ node.specifiers = node.specifiers.filter((specifier) => {
1639
+ let importedName = specifier.local.name;
1640
+ for (let retainedExportName of retainedExportNames) {
1641
+ let dependencies = exportDependencies.get(retainedExportName);
1642
+ if (dependencies?.importedIdentifierNames?.has(importedName)) {
1643
+ return true;
1644
+ }
1645
+ }
1646
+ for (let omittedExportName of omittedExportNames) {
1647
+ let dependencies = exportDependencies.get(omittedExportName);
1648
+ if (dependencies?.importedIdentifierNames?.has(importedName)) {
1649
+ return false;
1650
+ }
1651
+ }
1652
+ return true;
1653
+ });
1654
+ if (node.specifiers.length === 0) {
1655
+ return null;
1656
+ }
1657
+ return node;
1658
+ }).map((node) => {
1659
+ if (!t.isExportDeclaration(node)) {
1660
+ return node;
1661
+ }
1662
+ if (t.isExportAllDeclaration(node)) {
1663
+ return node;
1664
+ }
1665
+ if (t.isExportDefaultDeclaration(node)) {
1666
+ return isOmitted("default") ? null : node;
1667
+ }
1668
+ if (t.isVariableDeclaration(node.declaration)) {
1669
+ node.declaration.declarations = node.declaration.declarations.filter(
1670
+ (node2) => omittedExportedVariableDeclaratorsArray.every(
1671
+ (declarator) => !t.isNodesEquivalent(node2, declarator)
1672
+ )
1673
+ );
1674
+ if (node.declaration.declarations.length === 0) {
1675
+ return null;
1676
+ }
1677
+ return node;
1678
+ }
1679
+ if (t.isFunctionDeclaration(node.declaration) || t.isClassDeclaration(node.declaration)) {
1680
+ invariant(
1681
+ node.declaration.id,
1682
+ "Expected exported function or class declaration to have a name when not the default export"
1683
+ );
1684
+ return isOmitted(node.declaration.id.name) ? null : node;
1685
+ }
1686
+ if (t.isExportNamedDeclaration(node)) {
1687
+ if (node.specifiers.length === 0) {
1688
+ return node;
1689
+ }
1690
+ node.specifiers = node.specifiers.filter((specifier) => {
1691
+ const exportedName = getExportedName(specifier.exported);
1692
+ return !isOmitted(exportedName);
1693
+ });
1694
+ if (node.specifiers.length === 0) {
1695
+ return null;
1696
+ }
1697
+ return node;
1698
+ }
1699
+ throw new Error(`Unknown node type: ${node.type}`);
1700
+ }).filter((node) => node !== null);
1701
+ if (ast.program.body.length === 0) {
1702
+ return void 0;
1703
+ }
1704
+ return generate2(ast, generateOptions);
1705
+ }
1706
+ );
1707
+ }
1708
+ function detectRouteChunks(code, cache, cacheKey) {
1709
+ const hasRouteChunkByExportName = Object.fromEntries(
1710
+ routeChunkExportNames.map((exportName) => [
1711
+ exportName,
1712
+ hasChunkableExport(code, exportName, cache, cacheKey)
1713
+ ])
1714
+ );
1715
+ const chunkedExports = Object.entries(hasRouteChunkByExportName).filter(([, isChunked]) => isChunked).map(([exportName]) => exportName);
1716
+ const hasRouteChunks = chunkedExports.length > 0;
1717
+ return {
1718
+ hasRouteChunks,
1719
+ hasRouteChunkByExportName,
1720
+ chunkedExports
1721
+ };
1722
+ }
1723
+ var routeChunkExportNames = [
1724
+ "clientAction",
1725
+ "clientLoader",
1726
+ "HydrateFallback"
1727
+ ];
1728
+ var mainChunkName = "main";
1729
+ var routeChunkNames = ["main", ...routeChunkExportNames];
1730
+ function getRouteChunkCode(code, chunkName, cache, cacheKey) {
1731
+ if (chunkName === mainChunkName) {
1732
+ return omitChunkedExports(code, routeChunkExportNames, {}, cache, cacheKey);
1733
+ }
1734
+ return getChunkedExport(code, chunkName, {}, cache, cacheKey);
1735
+ }
1736
+ var routeChunkQueryStringPrefix = "?route-chunk=";
1737
+ var routeChunkQueryStrings = {
1738
+ main: `${routeChunkQueryStringPrefix}main`,
1739
+ clientAction: `${routeChunkQueryStringPrefix}clientAction`,
1740
+ clientLoader: `${routeChunkQueryStringPrefix}clientLoader`,
1741
+ HydrateFallback: `${routeChunkQueryStringPrefix}HydrateFallback`
1742
+ };
1743
+ function getRouteChunkModuleId(filePath, chunkName) {
1744
+ return `${filePath}${routeChunkQueryStrings[chunkName]}`;
1745
+ }
1746
+ function isRouteChunkModuleId(id) {
1747
+ return Object.values(routeChunkQueryStrings).some(
1748
+ (queryString) => id.endsWith(queryString)
1749
+ );
1750
+ }
1751
+ function isRouteChunkName(name) {
1752
+ return name === mainChunkName || routeChunkExportNames.includes(name);
1753
+ }
1754
+ function getRouteChunkNameFromModuleId(id) {
1755
+ if (!isRouteChunkModuleId(id)) {
1756
+ return null;
1757
+ }
1758
+ let chunkName = id.split(routeChunkQueryStringPrefix)[1].split("&")[0];
1759
+ if (!isRouteChunkName(chunkName)) {
1760
+ return null;
1761
+ }
1762
+ return chunkName;
1763
+ }
1764
+
1169
1765
  // vite/with-props.ts
1170
- var import_dedent3 = __toESM(require("dedent"));
1766
+ var import_dedent2 = __toESM(require("dedent"));
1171
1767
  var vmod = create("with-props");
1172
1768
  var NAMED_COMPONENT_EXPORTS = ["HydrateFallback", "ErrorBoundary"];
1173
1769
  var plugin = {
@@ -1178,7 +1774,7 @@ var plugin = {
1178
1774
  },
1179
1775
  async load(id) {
1180
1776
  if (id !== vmod.resolvedId) return;
1181
- return import_dedent3.default`
1777
+ return import_dedent2.default`
1182
1778
  import { createElement as h } from "react";
1183
1779
  import { useActionData, useLoaderData, useMatches, useParams, useRouteError } from "react-router";
1184
1780
 
@@ -1305,8 +1901,20 @@ var CLIENT_ROUTE_EXPORTS = [
1305
1901
  "shouldRevalidate"
1306
1902
  ];
1307
1903
  var BUILD_CLIENT_ROUTE_QUERY_STRING = "?__react-router-build-client-route";
1904
+ var isRouteEntryModuleId = (id) => {
1905
+ return id.endsWith(BUILD_CLIENT_ROUTE_QUERY_STRING);
1906
+ };
1907
+ var isRouteVirtualModule = (id) => {
1908
+ return isRouteEntryModuleId(id) || isRouteChunkModuleId(id);
1909
+ };
1308
1910
  var virtualHmrRuntime = create("hmr-runtime");
1309
1911
  var virtualInjectHmrRuntime = create("inject-hmr-runtime");
1912
+ var normalizeRelativeFilePath = (file, reactRouterConfig) => {
1913
+ let vite2 = getVite();
1914
+ let fullPath = path6.resolve(reactRouterConfig.appDirectory, file);
1915
+ let relativePath = path6.relative(reactRouterConfig.appDirectory, fullPath);
1916
+ return vite2.normalizePath(relativePath).split("?")[0];
1917
+ };
1310
1918
  var resolveRelativeRouteFilePath = (route, reactRouterConfig) => {
1311
1919
  let vite2 = getVite();
1312
1920
  let file = route.file;
@@ -1335,23 +1943,35 @@ var resolveChunk = (ctx, viteManifest, absoluteFilePath) => {
1335
1943
  let rootRelativeFilePath = vite2.normalizePath(
1336
1944
  path6.relative(ctx.rootDirectory, absoluteFilePath)
1337
1945
  );
1338
- let entryChunk = viteManifest[rootRelativeFilePath + BUILD_CLIENT_ROUTE_QUERY_STRING] ?? viteManifest[rootRelativeFilePath];
1946
+ let entryChunk = viteManifest[rootRelativeFilePath];
1339
1947
  if (!entryChunk) {
1340
- let knownManifestKeys = Object.keys(viteManifest).map((key) => '"' + key + '"').join(", ");
1341
- throw new Error(
1342
- `No manifest entry found for "${rootRelativeFilePath}". Known manifest keys: ${knownManifestKeys}`
1343
- );
1948
+ return void 0;
1344
1949
  }
1345
1950
  return entryChunk;
1346
1951
  };
1952
+ var getPublicModulePathForEntry = (ctx, viteManifest, entryFilePath) => {
1953
+ let entryChunk = resolveChunk(ctx, viteManifest, entryFilePath);
1954
+ return entryChunk ? `${ctx.publicPath}${entryChunk.file}` : void 0;
1955
+ };
1347
1956
  var getReactRouterManifestBuildAssets = (ctx, viteManifest, entryFilePath, prependedAssetFilePaths = []) => {
1348
1957
  let entryChunk = resolveChunk(ctx, viteManifest, entryFilePath);
1349
- let prependedAssetChunks = prependedAssetFilePaths.map(
1350
- (filePath) => resolveChunk(ctx, viteManifest, filePath)
1351
- );
1958
+ invariant(entryChunk, "Chunk not found");
1959
+ let prependedAssetChunks = prependedAssetFilePaths.map((filePath) => {
1960
+ let chunk = resolveChunk(ctx, viteManifest, filePath);
1961
+ invariant(chunk, "Chunk not found");
1962
+ return chunk;
1963
+ });
1964
+ let routeModuleChunks = routeChunkNames.map(
1965
+ (routeChunkName) => resolveChunk(
1966
+ ctx,
1967
+ viteManifest,
1968
+ getRouteChunkModuleId(entryFilePath.split("?")[0], routeChunkName)
1969
+ )
1970
+ ).filter(isNonNullable);
1352
1971
  let chunks = resolveDependantChunks(viteManifest, [
1353
1972
  ...prependedAssetChunks,
1354
- entryChunk
1973
+ entryChunk,
1974
+ ...routeModuleChunks
1355
1975
  ]);
1356
1976
  return {
1357
1977
  module: `${ctx.publicPath}${entryChunk.file}`,
@@ -1388,6 +2008,10 @@ var writeFileSafe = async (file, contents) => {
1388
2008
  await fse.ensureDir(path6.dirname(file));
1389
2009
  await fse.writeFile(file, contents);
1390
2010
  };
2011
+ var getExportNames = (code) => {
2012
+ let [, exportSpecifiers] = (0, import_es_module_lexer.parse)(code);
2013
+ return exportSpecifiers.map(({ n: name }) => name);
2014
+ };
1391
2015
  var getRouteManifestModuleExports = async (viteChildCompiler, ctx) => {
1392
2016
  let entries = await Promise.all(
1393
2017
  Object.entries(ctx.reactRouterConfig.routes).map(async ([key, route]) => {
@@ -1401,7 +2025,7 @@ var getRouteManifestModuleExports = async (viteChildCompiler, ctx) => {
1401
2025
  );
1402
2026
  return Object.fromEntries(entries);
1403
2027
  };
1404
- var getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
2028
+ var compileRouteFile = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
1405
2029
  if (!viteChildCompiler) {
1406
2030
  throw new Error("Vite child compiler not found");
1407
2031
  }
@@ -1421,9 +2045,19 @@ var getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteF
1421
2045
  moduleGraph.ensureEntryFromUrl(url2, ssr)
1422
2046
  ]);
1423
2047
  let transformed = await pluginContainer.transform(code, id, { ssr });
1424
- let [, exports2] = (0, import_es_module_lexer.parse)(transformed.code);
1425
- let exportNames = exports2.map((e) => e.n);
1426
- return exportNames;
2048
+ return transformed.code;
2049
+ };
2050
+ var getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
2051
+ if (!viteChildCompiler) {
2052
+ throw new Error("Vite child compiler not found");
2053
+ }
2054
+ let code = await compileRouteFile(
2055
+ viteChildCompiler,
2056
+ ctx,
2057
+ routeFile,
2058
+ readRouteFile
2059
+ );
2060
+ return getExportNames(code);
1427
2061
  };
1428
2062
  var getServerBundleBuildConfig = (viteUserConfig) => {
1429
2063
  if (!("__reactRouterServerBundleBuildConfig" in viteUserConfig) || !viteUserConfig.__reactRouterServerBundleBuildConfig) {
@@ -1443,7 +2077,7 @@ var defaultEntriesDir = path6.resolve(
1443
2077
  "config",
1444
2078
  "defaults"
1445
2079
  );
1446
- var defaultEntries = fse.readdirSync(defaultEntriesDir).map((filename2) => path6.join(defaultEntriesDir, filename2));
2080
+ var defaultEntries = fse.readdirSync(defaultEntriesDir).map((filename3) => path6.join(defaultEntriesDir, filename3));
1447
2081
  invariant(defaultEntries.length > 0, "No default entries found");
1448
2082
  var reactRouterDevLoadContext = () => ({});
1449
2083
  var reactRouterVitePlugin = () => {
@@ -1454,6 +2088,7 @@ var reactRouterVitePlugin = () => {
1454
2088
  let viteConfig;
1455
2089
  let cssModulesManifest = {};
1456
2090
  let viteChildCompiler = null;
2091
+ let cache = /* @__PURE__ */ new Map();
1457
2092
  let reactRouterConfigLoader;
1458
2093
  let typegenWatcherPromise;
1459
2094
  let logger;
@@ -1593,13 +2228,31 @@ var reactRouterVitePlugin = () => {
1593
2228
  viteChildCompiler,
1594
2229
  ctx
1595
2230
  );
2231
+ let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
1596
2232
  for (let [key, route] of Object.entries(ctx.reactRouterConfig.routes)) {
1597
- let routeFilePath = path6.join(
1598
- ctx.reactRouterConfig.appDirectory,
1599
- route.file
1600
- );
2233
+ let routeFile = path6.join(ctx.reactRouterConfig.appDirectory, route.file);
1601
2234
  let sourceExports = routeManifestExports[key];
1602
2235
  let isRootRoute = route.parentId === void 0;
2236
+ let hasClientAction = sourceExports.includes("clientAction");
2237
+ let hasClientLoader = sourceExports.includes("clientLoader");
2238
+ let hasHydrateFallback = sourceExports.includes("HydrateFallback");
2239
+ let { hasRouteChunkByExportName } = await detectRouteChunksIfEnabled(
2240
+ cache,
2241
+ ctx,
2242
+ routeFile,
2243
+ { routeFile, viteChildCompiler }
2244
+ );
2245
+ if (enforceSplitRouteModules) {
2246
+ validateRouteChunks({
2247
+ ctx,
2248
+ id: route.file,
2249
+ valid: {
2250
+ clientAction: !hasClientAction || hasRouteChunkByExportName.clientAction,
2251
+ clientLoader: !hasClientLoader || hasRouteChunkByExportName.clientLoader,
2252
+ HydrateFallback: !hasHydrateFallback || hasRouteChunkByExportName.HydrateFallback
2253
+ }
2254
+ });
2255
+ }
1603
2256
  let routeManifestEntry = {
1604
2257
  id: route.id,
1605
2258
  parentId: route.parentId,
@@ -1608,18 +2261,33 @@ var reactRouterVitePlugin = () => {
1608
2261
  caseSensitive: route.caseSensitive,
1609
2262
  hasAction: sourceExports.includes("action"),
1610
2263
  hasLoader: sourceExports.includes("loader"),
1611
- hasClientAction: sourceExports.includes("clientAction"),
1612
- hasClientLoader: sourceExports.includes("clientLoader"),
2264
+ hasClientAction,
2265
+ hasClientLoader,
1613
2266
  hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
1614
2267
  ...getReactRouterManifestBuildAssets(
1615
2268
  ctx,
1616
2269
  viteManifest,
1617
- routeFilePath,
2270
+ `${routeFile}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
1618
2271
  // If this is the root route, we also need to include assets from the
1619
2272
  // client entry file as this is a common way for consumers to import
1620
2273
  // global reset styles, etc.
1621
2274
  isRootRoute ? [ctx.entryClientFilePath] : []
1622
- )
2275
+ ),
2276
+ clientActionModule: hasRouteChunkByExportName.clientAction ? getPublicModulePathForEntry(
2277
+ ctx,
2278
+ viteManifest,
2279
+ getRouteChunkModuleId(routeFile, "clientAction")
2280
+ ) : void 0,
2281
+ clientLoaderModule: hasRouteChunkByExportName.clientLoader ? getPublicModulePathForEntry(
2282
+ ctx,
2283
+ viteManifest,
2284
+ getRouteChunkModuleId(routeFile, "clientLoader")
2285
+ ) : void 0,
2286
+ hydrateFallbackModule: hasRouteChunkByExportName.HydrateFallback ? getPublicModulePathForEntry(
2287
+ ctx,
2288
+ viteManifest,
2289
+ getRouteChunkModuleId(routeFile, "HydrateFallback")
2290
+ ) : void 0
1623
2291
  };
1624
2292
  browserRoutes[key] = routeManifestEntry;
1625
2293
  let serverBundleRoutes = ctx.serverBundleBuildConfig?.routes;
@@ -1660,25 +2328,52 @@ var reactRouterVitePlugin = () => {
1660
2328
  viteChildCompiler,
1661
2329
  ctx
1662
2330
  );
2331
+ let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
1663
2332
  for (let [key, route] of Object.entries(ctx.reactRouterConfig.routes)) {
2333
+ let routeFile = route.file;
1664
2334
  let sourceExports = routeManifestExports[key];
2335
+ let hasClientAction = sourceExports.includes("clientAction");
2336
+ let hasClientLoader = sourceExports.includes("clientLoader");
2337
+ let hasHydrateFallback = sourceExports.includes("HydrateFallback");
2338
+ let routeModulePath = combineURLs(
2339
+ ctx.publicPath,
2340
+ `${resolveFileUrl(
2341
+ ctx,
2342
+ resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
2343
+ )}`
2344
+ );
2345
+ if (enforceSplitRouteModules) {
2346
+ let { hasRouteChunkByExportName } = await detectRouteChunksIfEnabled(
2347
+ cache,
2348
+ ctx,
2349
+ routeFile,
2350
+ { routeFile, viteChildCompiler }
2351
+ );
2352
+ validateRouteChunks({
2353
+ ctx,
2354
+ id: route.file,
2355
+ valid: {
2356
+ clientAction: !hasClientAction || hasRouteChunkByExportName.clientAction,
2357
+ clientLoader: !hasClientLoader || hasRouteChunkByExportName.clientLoader,
2358
+ HydrateFallback: !hasHydrateFallback || hasRouteChunkByExportName.HydrateFallback
2359
+ }
2360
+ });
2361
+ }
1665
2362
  routes[key] = {
1666
2363
  id: route.id,
1667
2364
  parentId: route.parentId,
1668
2365
  path: route.path,
1669
2366
  index: route.index,
1670
2367
  caseSensitive: route.caseSensitive,
1671
- module: combineURLs(
1672
- ctx.publicPath,
1673
- resolveFileUrl(
1674
- ctx,
1675
- resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
1676
- )
1677
- ),
2368
+ module: routeModulePath,
2369
+ // Route chunks are a build-time optimization
2370
+ clientActionModule: void 0,
2371
+ clientLoaderModule: void 0,
2372
+ hydrateFallbackModule: void 0,
1678
2373
  hasAction: sourceExports.includes("action"),
1679
2374
  hasLoader: sourceExports.includes("loader"),
1680
- hasClientAction: sourceExports.includes("clientAction"),
1681
- hasClientLoader: sourceExports.includes("clientLoader"),
2375
+ hasClientAction,
2376
+ hasClientLoader,
1682
2377
  hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
1683
2378
  imports: []
1684
2379
  };
@@ -1711,8 +2406,13 @@ var reactRouterVitePlugin = () => {
1711
2406
  let viteClientConditions = [
1712
2407
  ...vite2.defaultClientConditions ?? []
1713
2408
  ];
2409
+ let packageRoot = path6.dirname(
2410
+ require.resolve("@react-router/dev/package.json")
2411
+ );
2412
+ let { moduleSyncEnabled } = await import(`file:///${path6.join(packageRoot, "module-sync-enabled/index.mjs")}`);
1714
2413
  let viteServerConditions = [
1715
- ...vite2.defaultServerConditions ?? []
2414
+ ...vite2.defaultServerConditions ?? [],
2415
+ ...moduleSyncEnabled ? ["module-sync"] : []
1716
2416
  ];
1717
2417
  logger = vite2.createLogger(viteUserConfig.logLevel, {
1718
2418
  prefix: "[react-router]"
@@ -1826,12 +2526,28 @@ var reactRouterVitePlugin = () => {
1826
2526
  preserveEntrySignatures: "exports-only",
1827
2527
  input: [
1828
2528
  ctx.entryClientFilePath,
1829
- ...Object.values(ctx.reactRouterConfig.routes).map(
1830
- (route) => `${path6.resolve(
2529
+ ...Object.values(
2530
+ ctx.reactRouterConfig.routes
2531
+ ).flatMap((route) => {
2532
+ let routeFilePath = path6.resolve(
1831
2533
  ctx.reactRouterConfig.appDirectory,
1832
2534
  route.file
1833
- )}${BUILD_CLIENT_ROUTE_QUERY_STRING}`
1834
- )
2535
+ );
2536
+ let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
2537
+ let code = fse.readFileSync(
2538
+ routeFilePath,
2539
+ "utf-8"
2540
+ );
2541
+ return [
2542
+ `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
2543
+ ...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
2544
+ (exportName) => code.includes(exportName) ? getRouteChunkModuleId(
2545
+ routeFilePath,
2546
+ exportName
2547
+ ) : null
2548
+ ) : []
2549
+ ].filter(isNonNullable);
2550
+ })
1835
2551
  ]
1836
2552
  }
1837
2553
  } : {
@@ -2099,10 +2815,59 @@ var reactRouterVitePlugin = () => {
2099
2815
  await typegenWatcher?.close();
2100
2816
  }
2101
2817
  },
2818
+ {
2819
+ name: "react-router:route-chunks-index",
2820
+ // This plugin provides the route module "index" since route modules can
2821
+ // be chunked and may be made up of multiple smaller modules. This plugin
2822
+ // primarily ensures code is never duplicated across a route module and
2823
+ // its chunks. If we didn't have this plugin, any app that explicitly
2824
+ // imports a route module would result in duplicate code since the app
2825
+ // would contain code for both the unprocessed route module as well as its
2826
+ // individual chunks. This is because, since they have different module
2827
+ // IDs, they are treated as completely separate modules even though they
2828
+ // all reference the same underlying file. This plugin addresses this by
2829
+ // ensuring that any explicit imports of a route module resolve to a
2830
+ // module that simply re-exports from its underlying chunks, if present.
2831
+ async transform(code, id, options) {
2832
+ if (viteCommand !== "build") return;
2833
+ if (options?.ssr) {
2834
+ return;
2835
+ }
2836
+ if (!isRoute(ctx.reactRouterConfig, id)) {
2837
+ return;
2838
+ }
2839
+ if (isRouteVirtualModule(id)) {
2840
+ return;
2841
+ }
2842
+ let { hasRouteChunks, chunkedExports } = await detectRouteChunksIfEnabled(cache, ctx, id, code);
2843
+ if (!hasRouteChunks) {
2844
+ return;
2845
+ }
2846
+ let sourceExports = await getRouteModuleExports(
2847
+ viteChildCompiler,
2848
+ ctx,
2849
+ id
2850
+ );
2851
+ let isMainChunkExport = (name) => !chunkedExports.includes(name);
2852
+ let mainChunkReexports = sourceExports.filter(isMainChunkExport).join(", ");
2853
+ let chunkBasePath = `./${path6.basename(id)}`;
2854
+ return [
2855
+ `export { ${mainChunkReexports} } from "${getRouteChunkModuleId(
2856
+ chunkBasePath,
2857
+ "main"
2858
+ )}";`,
2859
+ ...chunkedExports.map(
2860
+ (exportName) => `export { ${exportName} } from "${getRouteChunkModuleId(
2861
+ chunkBasePath,
2862
+ exportName
2863
+ )}";`
2864
+ )
2865
+ ].filter(Boolean).join("\n");
2866
+ }
2867
+ },
2102
2868
  {
2103
2869
  name: "react-router:build-client-route",
2104
- enforce: "pre",
2105
- async transform(_code, id, options) {
2870
+ async transform(code, id, options) {
2106
2871
  if (!id.endsWith(BUILD_CLIENT_ROUTE_QUERY_STRING)) return;
2107
2872
  let routeModuleId = id.replace(BUILD_CLIENT_ROUTE_QUERY_STRING, "");
2108
2873
  let routeFileName = path6.basename(routeModuleId);
@@ -2111,12 +2876,53 @@ var reactRouterVitePlugin = () => {
2111
2876
  ctx,
2112
2877
  routeModuleId
2113
2878
  );
2114
- let reexports = sourceExports.filter(
2115
- (exportName) => options?.ssr && SERVER_ONLY_ROUTE_EXPORTS.includes(exportName) || CLIENT_ROUTE_EXPORTS.includes(exportName)
2116
- ).join(", ");
2879
+ let { chunkedExports = [] } = options?.ssr ? {} : await detectRouteChunksIfEnabled(cache, ctx, id, code);
2880
+ let reexports = sourceExports.filter((exportName) => {
2881
+ let isRouteEntryExport = options?.ssr && SERVER_ONLY_ROUTE_EXPORTS.includes(exportName) || CLIENT_ROUTE_EXPORTS.includes(exportName);
2882
+ let isChunkedExport = chunkedExports.includes(
2883
+ exportName
2884
+ );
2885
+ return isRouteEntryExport && !isChunkedExport;
2886
+ }).join(", ");
2117
2887
  return `export { ${reexports} } from "./${routeFileName}";`;
2118
2888
  }
2119
2889
  },
2890
+ {
2891
+ name: "react-router:route-chunks",
2892
+ async transform(code, id, options) {
2893
+ if (options?.ssr) return;
2894
+ if (!isRouteChunkModuleId(id)) return;
2895
+ let chunkName = getRouteChunkNameFromModuleId(id);
2896
+ if (!chunkName) {
2897
+ throw new Error(`Invalid route chunk name "${chunkName}" in "${id}"`);
2898
+ }
2899
+ let chunk = await getRouteChunkIfEnabled(
2900
+ cache,
2901
+ ctx,
2902
+ id,
2903
+ chunkName,
2904
+ code
2905
+ );
2906
+ let preventEmptyChunkSnippet = ({ reason }) => `Math.random()<0&&console.log(${JSON.stringify(reason)});`;
2907
+ if (chunk === null) {
2908
+ return preventEmptyChunkSnippet({ reason: "Route chunks disabled" });
2909
+ }
2910
+ let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
2911
+ if (enforceSplitRouteModules && chunkName === "main" && chunk) {
2912
+ let exportNames = getExportNames(chunk.code);
2913
+ validateRouteChunks({
2914
+ ctx,
2915
+ id,
2916
+ valid: {
2917
+ clientAction: !exportNames.includes("clientAction"),
2918
+ clientLoader: !exportNames.includes("clientLoader"),
2919
+ HydrateFallback: !exportNames.includes("HydrateFallback")
2920
+ }
2921
+ });
2922
+ }
2923
+ return chunk ?? preventEmptyChunkSnippet({ reason: `No ${chunkName} chunk` });
2924
+ }
2925
+ },
2120
2926
  {
2121
2927
  name: "react-router:virtual-modules",
2122
2928
  enforce: "pre",
@@ -2171,8 +2977,7 @@ var reactRouterVitePlugin = () => {
2171
2977
  let importerShort = vite2.normalizePath(
2172
2978
  path6.relative(ctx.rootDirectory, importer)
2173
2979
  );
2174
- let isRoute = getRoute(ctx.reactRouterConfig, importer);
2175
- if (isRoute) {
2980
+ if (isRoute(ctx.reactRouterConfig, importer)) {
2176
2981
  let serverOnlyExports = SERVER_ONLY_ROUTE_EXPORTS.map(
2177
2982
  (xport) => `\`${xport}\``
2178
2983
  ).join(", ");
@@ -2211,10 +3016,10 @@ var reactRouterVitePlugin = () => {
2211
3016
  let clientFileRE = /\.client(\.[cm]?[jt]sx?)?$/;
2212
3017
  let clientDirRE = /\/\.client\//;
2213
3018
  if (clientFileRE.test(id) || clientDirRE.test(id)) {
2214
- let exports2 = (0, import_es_module_lexer.parse)(code)[1];
3019
+ let exports2 = getExportNames(code);
2215
3020
  return {
2216
3021
  code: exports2.map(
2217
- ({ n: name }) => name === "default" ? "export default undefined;" : `export const ${name} = undefined;`
3022
+ (name) => name === "default" ? "export default undefined;" : `export const ${name} = undefined;`
2218
3023
  ).join("\n"),
2219
3024
  map: null
2220
3025
  };
@@ -2225,17 +3030,25 @@ var reactRouterVitePlugin = () => {
2225
3030
  {
2226
3031
  name: "react-router:route-exports",
2227
3032
  async transform(code, id, options) {
3033
+ if (isRouteChunkModuleId(id)) {
3034
+ id = id.split("?")[0];
3035
+ }
2228
3036
  let route = getRoute(ctx.reactRouterConfig, id);
2229
3037
  if (!route) return;
2230
3038
  if (!options?.ssr && !ctx.reactRouterConfig.ssr) {
2231
- let serverOnlyExports = (0, import_es_module_lexer.parse)(code)[1].map((exp) => exp.n).filter((exp) => SERVER_ONLY_ROUTE_EXPORTS.includes(exp));
3039
+ let exportNames = getExportNames(code);
3040
+ let serverOnlyExports = exportNames.filter(
3041
+ (exp) => SERVER_ONLY_ROUTE_EXPORTS.includes(exp)
3042
+ );
2232
3043
  if (serverOnlyExports.length > 0) {
2233
3044
  let str = serverOnlyExports.map((e) => `\`${e}\``).join(", ");
2234
3045
  let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://remix.run/guides/spa-mode for more information.`;
2235
3046
  throw Error(message);
2236
3047
  }
2237
3048
  if (route.id !== "root") {
2238
- let hasHydrateFallback = (0, import_es_module_lexer.parse)(code)[1].map((exp) => exp.n).some((exp) => exp === "HydrateFallback");
3049
+ let hasHydrateFallback = exportNames.some(
3050
+ (exp) => exp === "HydrateFallback"
3051
+ );
2239
3052
  if (hasHydrateFallback) {
2240
3053
  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.`;
2241
3054
  throw Error(message);
@@ -2313,6 +3126,9 @@ var reactRouterVitePlugin = () => {
2313
3126
  let isJSX = filepath.endsWith("x");
2314
3127
  let useFastRefresh = !ssr && (isJSX || code.includes(devRuntime));
2315
3128
  if (!useFastRefresh) return;
3129
+ if (isRouteVirtualModule(id)) {
3130
+ return { code: addRefreshWrapper(ctx.reactRouterConfig, code, id) };
3131
+ }
2316
3132
  let result = await babel.transformAsync(code, {
2317
3133
  babelrc: false,
2318
3134
  configFile: false,
@@ -2343,6 +3159,7 @@ var reactRouterVitePlugin = () => {
2343
3159
  let serverManifest = (await server.ssrLoadModule(virtual.serverManifest.id)).default;
2344
3160
  let oldRouteMetadata = serverManifest.routes[route.id];
2345
3161
  let newRouteMetadata = await getRouteMetadata(
3162
+ cache,
2346
3163
  ctx,
2347
3164
  viteChildCompiler,
2348
3165
  route,
@@ -2352,9 +3169,12 @@ var reactRouterVitePlugin = () => {
2352
3169
  if (!oldRouteMetadata || [
2353
3170
  "hasLoader",
2354
3171
  "hasClientLoader",
3172
+ "clientLoaderModule",
2355
3173
  "hasAction",
2356
3174
  "hasClientAction",
2357
- "hasErrorBoundary"
3175
+ "clientActionModule",
3176
+ "hasErrorBoundary",
3177
+ "hydrateFallbackModule"
2358
3178
  ].some((key) => oldRouteMetadata[key] !== newRouteMetadata[key])) {
2359
3179
  invalidateVirtualModules(server);
2360
3180
  }
@@ -2472,13 +3292,30 @@ function getRoute(pluginConfig, file) {
2472
3292
  );
2473
3293
  return route;
2474
3294
  }
2475
- async function getRouteMetadata(ctx, viteChildCompiler, route, readRouteFile) {
3295
+ function isRoute(pluginConfig, file) {
3296
+ return Boolean(getRoute(pluginConfig, file));
3297
+ }
3298
+ async function getRouteMetadata(cache, ctx, viteChildCompiler, route, readRouteFile) {
3299
+ let routeFile = route.file;
2476
3300
  let sourceExports = await getRouteModuleExports(
2477
3301
  viteChildCompiler,
2478
3302
  ctx,
2479
3303
  route.file,
2480
3304
  readRouteFile
2481
3305
  );
3306
+ let { hasRouteChunkByExportName } = await detectRouteChunksIfEnabled(
3307
+ cache,
3308
+ ctx,
3309
+ routeFile,
3310
+ { routeFile, readRouteFile, viteChildCompiler }
3311
+ );
3312
+ let moduleUrl = combineURLs(
3313
+ ctx.publicPath,
3314
+ `${resolveFileUrl(
3315
+ ctx,
3316
+ resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
3317
+ )}`
3318
+ );
2482
3319
  let info = {
2483
3320
  id: route.id,
2484
3321
  parentId: route.parentId,
@@ -2492,14 +3329,11 @@ async function getRouteMetadata(ctx, viteChildCompiler, route, readRouteFile) {
2492
3329
  resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
2493
3330
  )
2494
3331
  ),
2495
- module: combineURLs(
2496
- ctx.publicPath,
2497
- `${resolveFileUrl(
2498
- ctx,
2499
- resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
2500
- )}?import`
2501
- ),
3332
+ module: `${moduleUrl}?import`,
2502
3333
  // Ensure the Vite dev server responds with a JS module
3334
+ clientActionModule: hasRouteChunkByExportName.clientAction ? `${getRouteChunkModuleId(moduleUrl, "clientAction")}` : void 0,
3335
+ clientLoaderModule: hasRouteChunkByExportName.clientLoader ? `${getRouteChunkModuleId(moduleUrl, "clientLoader")}` : void 0,
3336
+ hydrateFallbackModule: hasRouteChunkByExportName.HydrateFallback ? `${getRouteChunkModuleId(moduleUrl, "HydrateFallback")}` : void 0,
2503
3337
  hasAction: sourceExports.includes("action"),
2504
3338
  hasClientAction: sourceExports.includes("clientAction"),
2505
3339
  hasLoader: sourceExports.includes("loader"),
@@ -2748,6 +3582,73 @@ function createPrerenderRoutes(manifest, parentId = "", routesByParentId = group
2748
3582
  };
2749
3583
  });
2750
3584
  }
3585
+ var resolveRouteFileCode = async (ctx, input) => {
3586
+ if (typeof input === "string") return input;
3587
+ invariant(input.viteChildCompiler);
3588
+ return await compileRouteFile(
3589
+ input.viteChildCompiler,
3590
+ ctx,
3591
+ input.routeFile,
3592
+ input.readRouteFile
3593
+ );
3594
+ };
3595
+ async function detectRouteChunksIfEnabled(cache, ctx, id, input) {
3596
+ function noRouteChunks() {
3597
+ return {
3598
+ chunkedExports: [],
3599
+ hasRouteChunks: false,
3600
+ hasRouteChunkByExportName: {
3601
+ clientAction: false,
3602
+ clientLoader: false,
3603
+ HydrateFallback: false
3604
+ }
3605
+ };
3606
+ }
3607
+ if (!ctx.reactRouterConfig.future.unstable_splitRouteModules) {
3608
+ return noRouteChunks();
3609
+ }
3610
+ if (normalizeRelativeFilePath(id, ctx.reactRouterConfig) === ctx.reactRouterConfig.routes.root.file) {
3611
+ return noRouteChunks();
3612
+ }
3613
+ let code = await resolveRouteFileCode(ctx, input);
3614
+ if (!routeChunkExportNames.some((exportName) => code.includes(exportName))) {
3615
+ return noRouteChunks();
3616
+ }
3617
+ let cacheKey = normalizeRelativeFilePath(id, ctx.reactRouterConfig) + (typeof input === "string" ? "" : "?read");
3618
+ return detectRouteChunks(code, cache, cacheKey);
3619
+ }
3620
+ async function getRouteChunkIfEnabled(cache, ctx, id, chunkName, input) {
3621
+ if (!ctx.reactRouterConfig.future.unstable_splitRouteModules) {
3622
+ return null;
3623
+ }
3624
+ let code = await resolveRouteFileCode(ctx, input);
3625
+ let cacheKey = normalizeRelativeFilePath(id, ctx.reactRouterConfig) + (typeof input === "string" ? "" : "?read");
3626
+ return getRouteChunkCode(code, chunkName, cache, cacheKey);
3627
+ }
3628
+ function validateRouteChunks({
3629
+ ctx,
3630
+ id,
3631
+ valid
3632
+ }) {
3633
+ let invalidChunks = Object.entries(valid).filter(([_, isValid]) => !isValid).map(([chunkName]) => chunkName);
3634
+ if (invalidChunks.length === 0) {
3635
+ return;
3636
+ }
3637
+ let plural = invalidChunks.length > 1;
3638
+ throw new Error(
3639
+ [
3640
+ `Error splitting route module: ${normalizeRelativeFilePath(
3641
+ id,
3642
+ ctx.reactRouterConfig
3643
+ )}`,
3644
+ invalidChunks.map((name) => `- ${name}`).join("\n"),
3645
+ `${plural ? "These exports" : "This export"} could not be split into ${plural ? "their own chunks" : "its own chunk"} because ${plural ? "they share" : "it shares"} code with other exports. You should extract any shared code into its own module and then import it within the route module.`
3646
+ ].join("\n\n")
3647
+ );
3648
+ }
3649
+ function isNonNullable(x) {
3650
+ return x != null;
3651
+ }
2751
3652
  // Annotate the CommonJS export names for ESM import in node:
2752
3653
  0 && (module.exports = {
2753
3654
  reactRouter