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

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-d312c78a4
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_routeChunks: userFuture?.unstable_routeChunks ?? 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 enforceRouteChunks = ctx.reactRouterConfig.future.unstable_routeChunks === "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 (enforceRouteChunks) {
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 enforceRouteChunks = ctx.reactRouterConfig.future.unstable_routeChunks === "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 (enforceRouteChunks) {
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
  };
@@ -1826,12 +2521,28 @@ var reactRouterVitePlugin = () => {
1826
2521
  preserveEntrySignatures: "exports-only",
1827
2522
  input: [
1828
2523
  ctx.entryClientFilePath,
1829
- ...Object.values(ctx.reactRouterConfig.routes).map(
1830
- (route) => `${path6.resolve(
2524
+ ...Object.values(
2525
+ ctx.reactRouterConfig.routes
2526
+ ).flatMap((route) => {
2527
+ let routeFilePath = path6.resolve(
1831
2528
  ctx.reactRouterConfig.appDirectory,
1832
2529
  route.file
1833
- )}${BUILD_CLIENT_ROUTE_QUERY_STRING}`
1834
- )
2530
+ );
2531
+ let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
2532
+ let code = fse.readFileSync(
2533
+ routeFilePath,
2534
+ "utf-8"
2535
+ );
2536
+ return [
2537
+ `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
2538
+ ...!isRootRoute ? routeChunkExportNames.map(
2539
+ (exportName) => code.includes(exportName) ? getRouteChunkModuleId(
2540
+ routeFilePath,
2541
+ exportName
2542
+ ) : null
2543
+ ) : []
2544
+ ].filter(isNonNullable);
2545
+ })
1835
2546
  ]
1836
2547
  }
1837
2548
  } : {
@@ -2099,10 +2810,59 @@ var reactRouterVitePlugin = () => {
2099
2810
  await typegenWatcher?.close();
2100
2811
  }
2101
2812
  },
2813
+ {
2814
+ name: "react-router:route-chunks-index",
2815
+ // This plugin provides the route module "index" since route modules can
2816
+ // be chunked and may be made up of multiple smaller modules. This plugin
2817
+ // primarily ensures code is never duplicated across a route module and
2818
+ // its chunks. If we didn't have this plugin, any app that explicitly
2819
+ // imports a route module would result in duplicate code since the app
2820
+ // would contain code for both the unprocessed route module as well as its
2821
+ // individual chunks. This is because, since they have different module
2822
+ // IDs, they are treated as completely separate modules even though they
2823
+ // all reference the same underlying file. This plugin addresses this by
2824
+ // ensuring that any explicit imports of a route module resolve to a
2825
+ // module that simply re-exports from its underlying chunks, if present.
2826
+ async transform(code, id, options) {
2827
+ if (viteCommand !== "build") return;
2828
+ if (options?.ssr) {
2829
+ return;
2830
+ }
2831
+ if (!isRoute(ctx.reactRouterConfig, id)) {
2832
+ return;
2833
+ }
2834
+ if (isRouteVirtualModule(id)) {
2835
+ return;
2836
+ }
2837
+ let { hasRouteChunks, chunkedExports } = await detectRouteChunksIfEnabled(cache, ctx, id, code);
2838
+ if (!hasRouteChunks) {
2839
+ return;
2840
+ }
2841
+ let sourceExports = await getRouteModuleExports(
2842
+ viteChildCompiler,
2843
+ ctx,
2844
+ id
2845
+ );
2846
+ let isMainChunkExport = (name) => !chunkedExports.includes(name);
2847
+ let mainChunkReexports = sourceExports.filter(isMainChunkExport).join(", ");
2848
+ let chunkBasePath = `./${path6.basename(id)}`;
2849
+ return [
2850
+ `export { ${mainChunkReexports} } from "${getRouteChunkModuleId(
2851
+ chunkBasePath,
2852
+ "main"
2853
+ )}";`,
2854
+ ...chunkedExports.map(
2855
+ (exportName) => `export { ${exportName} } from "${getRouteChunkModuleId(
2856
+ chunkBasePath,
2857
+ exportName
2858
+ )}";`
2859
+ )
2860
+ ].filter(Boolean).join("\n");
2861
+ }
2862
+ },
2102
2863
  {
2103
2864
  name: "react-router:build-client-route",
2104
- enforce: "pre",
2105
- async transform(_code, id, options) {
2865
+ async transform(code, id, options) {
2106
2866
  if (!id.endsWith(BUILD_CLIENT_ROUTE_QUERY_STRING)) return;
2107
2867
  let routeModuleId = id.replace(BUILD_CLIENT_ROUTE_QUERY_STRING, "");
2108
2868
  let routeFileName = path6.basename(routeModuleId);
@@ -2111,12 +2871,53 @@ var reactRouterVitePlugin = () => {
2111
2871
  ctx,
2112
2872
  routeModuleId
2113
2873
  );
2114
- let reexports = sourceExports.filter(
2115
- (exportName) => options?.ssr && SERVER_ONLY_ROUTE_EXPORTS.includes(exportName) || CLIENT_ROUTE_EXPORTS.includes(exportName)
2116
- ).join(", ");
2874
+ let { chunkedExports = [] } = options?.ssr ? {} : await detectRouteChunksIfEnabled(cache, ctx, id, code);
2875
+ let reexports = sourceExports.filter((exportName) => {
2876
+ let isRouteEntryExport = options?.ssr && SERVER_ONLY_ROUTE_EXPORTS.includes(exportName) || CLIENT_ROUTE_EXPORTS.includes(exportName);
2877
+ let isChunkedExport = chunkedExports.includes(
2878
+ exportName
2879
+ );
2880
+ return isRouteEntryExport && !isChunkedExport;
2881
+ }).join(", ");
2117
2882
  return `export { ${reexports} } from "./${routeFileName}";`;
2118
2883
  }
2119
2884
  },
2885
+ {
2886
+ name: "react-router:route-chunks",
2887
+ async transform(code, id, options) {
2888
+ if (options?.ssr) return;
2889
+ if (!isRouteChunkModuleId(id)) return;
2890
+ let chunkName = getRouteChunkNameFromModuleId(id);
2891
+ if (!chunkName) {
2892
+ throw new Error(`Invalid route chunk name "${chunkName}" in "${id}"`);
2893
+ }
2894
+ let chunk = await getRouteChunkIfEnabled(
2895
+ cache,
2896
+ ctx,
2897
+ id,
2898
+ chunkName,
2899
+ code
2900
+ );
2901
+ let preventEmptyChunkSnippet = ({ reason }) => `Math.random()<0&&console.log(${JSON.stringify(reason)});`;
2902
+ if (chunk === null) {
2903
+ return preventEmptyChunkSnippet({ reason: "Route chunks disabled" });
2904
+ }
2905
+ let enforceRouteChunks = ctx.reactRouterConfig.future.unstable_routeChunks === "enforce";
2906
+ if (enforceRouteChunks && chunkName === "main" && chunk) {
2907
+ let exportNames = getExportNames(chunk.code);
2908
+ validateRouteChunks({
2909
+ ctx,
2910
+ id,
2911
+ valid: {
2912
+ clientAction: !exportNames.includes("clientAction"),
2913
+ clientLoader: !exportNames.includes("clientLoader"),
2914
+ HydrateFallback: !exportNames.includes("HydrateFallback")
2915
+ }
2916
+ });
2917
+ }
2918
+ return chunk ?? preventEmptyChunkSnippet({ reason: `No ${chunkName} chunk` });
2919
+ }
2920
+ },
2120
2921
  {
2121
2922
  name: "react-router:virtual-modules",
2122
2923
  enforce: "pre",
@@ -2171,8 +2972,7 @@ var reactRouterVitePlugin = () => {
2171
2972
  let importerShort = vite2.normalizePath(
2172
2973
  path6.relative(ctx.rootDirectory, importer)
2173
2974
  );
2174
- let isRoute = getRoute(ctx.reactRouterConfig, importer);
2175
- if (isRoute) {
2975
+ if (isRoute(ctx.reactRouterConfig, importer)) {
2176
2976
  let serverOnlyExports = SERVER_ONLY_ROUTE_EXPORTS.map(
2177
2977
  (xport) => `\`${xport}\``
2178
2978
  ).join(", ");
@@ -2211,10 +3011,10 @@ var reactRouterVitePlugin = () => {
2211
3011
  let clientFileRE = /\.client(\.[cm]?[jt]sx?)?$/;
2212
3012
  let clientDirRE = /\/\.client\//;
2213
3013
  if (clientFileRE.test(id) || clientDirRE.test(id)) {
2214
- let exports2 = (0, import_es_module_lexer.parse)(code)[1];
3014
+ let exports2 = getExportNames(code);
2215
3015
  return {
2216
3016
  code: exports2.map(
2217
- ({ n: name }) => name === "default" ? "export default undefined;" : `export const ${name} = undefined;`
3017
+ (name) => name === "default" ? "export default undefined;" : `export const ${name} = undefined;`
2218
3018
  ).join("\n"),
2219
3019
  map: null
2220
3020
  };
@@ -2228,14 +3028,19 @@ var reactRouterVitePlugin = () => {
2228
3028
  let route = getRoute(ctx.reactRouterConfig, id);
2229
3029
  if (!route) return;
2230
3030
  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));
3031
+ let exportNames = getExportNames(code);
3032
+ let serverOnlyExports = exportNames.filter(
3033
+ (exp) => SERVER_ONLY_ROUTE_EXPORTS.includes(exp)
3034
+ );
2232
3035
  if (serverOnlyExports.length > 0) {
2233
3036
  let str = serverOnlyExports.map((e) => `\`${e}\``).join(", ");
2234
3037
  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
3038
  throw Error(message);
2236
3039
  }
2237
3040
  if (route.id !== "root") {
2238
- let hasHydrateFallback = (0, import_es_module_lexer.parse)(code)[1].map((exp) => exp.n).some((exp) => exp === "HydrateFallback");
3041
+ let hasHydrateFallback = exportNames.some(
3042
+ (exp) => exp === "HydrateFallback"
3043
+ );
2239
3044
  if (hasHydrateFallback) {
2240
3045
  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
3046
  throw Error(message);
@@ -2313,6 +3118,9 @@ var reactRouterVitePlugin = () => {
2313
3118
  let isJSX = filepath.endsWith("x");
2314
3119
  let useFastRefresh = !ssr && (isJSX || code.includes(devRuntime));
2315
3120
  if (!useFastRefresh) return;
3121
+ if (isRouteVirtualModule(id)) {
3122
+ return { code: addRefreshWrapper(ctx.reactRouterConfig, code, id) };
3123
+ }
2316
3124
  let result = await babel.transformAsync(code, {
2317
3125
  babelrc: false,
2318
3126
  configFile: false,
@@ -2343,6 +3151,7 @@ var reactRouterVitePlugin = () => {
2343
3151
  let serverManifest = (await server.ssrLoadModule(virtual.serverManifest.id)).default;
2344
3152
  let oldRouteMetadata = serverManifest.routes[route.id];
2345
3153
  let newRouteMetadata = await getRouteMetadata(
3154
+ cache,
2346
3155
  ctx,
2347
3156
  viteChildCompiler,
2348
3157
  route,
@@ -2352,9 +3161,12 @@ var reactRouterVitePlugin = () => {
2352
3161
  if (!oldRouteMetadata || [
2353
3162
  "hasLoader",
2354
3163
  "hasClientLoader",
3164
+ "clientLoaderModule",
2355
3165
  "hasAction",
2356
3166
  "hasClientAction",
2357
- "hasErrorBoundary"
3167
+ "clientActionModule",
3168
+ "hasErrorBoundary",
3169
+ "hydrateFallbackModule"
2358
3170
  ].some((key) => oldRouteMetadata[key] !== newRouteMetadata[key])) {
2359
3171
  invalidateVirtualModules(server);
2360
3172
  }
@@ -2472,13 +3284,30 @@ function getRoute(pluginConfig, file) {
2472
3284
  );
2473
3285
  return route;
2474
3286
  }
2475
- async function getRouteMetadata(ctx, viteChildCompiler, route, readRouteFile) {
3287
+ function isRoute(pluginConfig, file) {
3288
+ return Boolean(getRoute(pluginConfig, file));
3289
+ }
3290
+ async function getRouteMetadata(cache, ctx, viteChildCompiler, route, readRouteFile) {
3291
+ let routeFile = route.file;
2476
3292
  let sourceExports = await getRouteModuleExports(
2477
3293
  viteChildCompiler,
2478
3294
  ctx,
2479
3295
  route.file,
2480
3296
  readRouteFile
2481
3297
  );
3298
+ let { hasRouteChunkByExportName } = await detectRouteChunksIfEnabled(
3299
+ cache,
3300
+ ctx,
3301
+ routeFile,
3302
+ { routeFile, readRouteFile, viteChildCompiler }
3303
+ );
3304
+ let moduleUrl = combineURLs(
3305
+ ctx.publicPath,
3306
+ `${resolveFileUrl(
3307
+ ctx,
3308
+ resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
3309
+ )}`
3310
+ );
2482
3311
  let info = {
2483
3312
  id: route.id,
2484
3313
  parentId: route.parentId,
@@ -2492,14 +3321,11 @@ async function getRouteMetadata(ctx, viteChildCompiler, route, readRouteFile) {
2492
3321
  resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
2493
3322
  )
2494
3323
  ),
2495
- module: combineURLs(
2496
- ctx.publicPath,
2497
- `${resolveFileUrl(
2498
- ctx,
2499
- resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
2500
- )}?import`
2501
- ),
3324
+ module: `${moduleUrl}?import`,
2502
3325
  // Ensure the Vite dev server responds with a JS module
3326
+ clientActionModule: hasRouteChunkByExportName.clientAction ? `${getRouteChunkModuleId(moduleUrl, "clientAction")}` : void 0,
3327
+ clientLoaderModule: hasRouteChunkByExportName.clientLoader ? `${getRouteChunkModuleId(moduleUrl, "clientLoader")}` : void 0,
3328
+ hydrateFallbackModule: hasRouteChunkByExportName.HydrateFallback ? `${getRouteChunkModuleId(moduleUrl, "HydrateFallback")}` : void 0,
2503
3329
  hasAction: sourceExports.includes("action"),
2504
3330
  hasClientAction: sourceExports.includes("clientAction"),
2505
3331
  hasLoader: sourceExports.includes("loader"),
@@ -2748,6 +3574,74 @@ function createPrerenderRoutes(manifest, parentId = "", routesByParentId = group
2748
3574
  };
2749
3575
  });
2750
3576
  }
3577
+ var resolveRouteFileCode = async (ctx, input) => {
3578
+ if (typeof input === "string") return input;
3579
+ invariant(input.viteChildCompiler);
3580
+ return await compileRouteFile(
3581
+ input.viteChildCompiler,
3582
+ ctx,
3583
+ input.routeFile,
3584
+ input.readRouteFile
3585
+ );
3586
+ };
3587
+ async function detectRouteChunksIfEnabled(cache, ctx, id, input) {
3588
+ function noRouteChunks() {
3589
+ return {
3590
+ chunkedExports: [],
3591
+ hasRouteChunks: false,
3592
+ hasRouteChunkByExportName: {
3593
+ clientAction: false,
3594
+ clientLoader: false,
3595
+ HydrateFallback: false
3596
+ }
3597
+ };
3598
+ }
3599
+ if (!ctx.reactRouterConfig.future.unstable_routeChunks) {
3600
+ return noRouteChunks();
3601
+ }
3602
+ if (normalizeRelativeFilePath(id, ctx.reactRouterConfig) === ctx.reactRouterConfig.routes.root.file) {
3603
+ return noRouteChunks();
3604
+ }
3605
+ let code = await resolveRouteFileCode(ctx, input);
3606
+ if (!routeChunkExportNames.some((exportName) => code.includes(exportName))) {
3607
+ return noRouteChunks();
3608
+ }
3609
+ let cacheKey = normalizeRelativeFilePath(id, ctx.reactRouterConfig) + (typeof input === "string" ? "" : "?read");
3610
+ return detectRouteChunks(code, cache, cacheKey);
3611
+ }
3612
+ async function getRouteChunkIfEnabled(cache, ctx, id, chunkName, input) {
3613
+ if (!ctx.reactRouterConfig.future.unstable_routeChunks) {
3614
+ return null;
3615
+ }
3616
+ let code = await resolveRouteFileCode(ctx, input);
3617
+ let cacheKey = normalizeRelativeFilePath(id, ctx.reactRouterConfig) + (typeof input === "string" ? "" : "?read");
3618
+ return getRouteChunkCode(code, chunkName, cache, cacheKey);
3619
+ }
3620
+ function validateRouteChunks({
3621
+ ctx,
3622
+ id,
3623
+ valid
3624
+ }) {
3625
+ let invalidChunks = Object.entries(valid).filter(([_, isValid]) => !isValid).map(([chunkName]) => chunkName);
3626
+ if (invalidChunks.length === 0) {
3627
+ return;
3628
+ }
3629
+ let plural = invalidChunks.length > 1;
3630
+ throw new Error(
3631
+ [
3632
+ `Route chunks error: ${normalizeRelativeFilePath(
3633
+ id,
3634
+ ctx.reactRouterConfig
3635
+ )}`,
3636
+ invalidChunks.map((name) => `- ${name}`).join("\n"),
3637
+ `${plural ? `These exports were` : `This export was`} unable to be split into ${plural ? "their own chunks" : "its own chunk"} because ${plural ? "they reference" : "it references"} code in the same file that is used by other route module exports.`,
3638
+ `If you need to share code between ${plural ? `these` : `this`} and other exports, you should extract the shared code into a separate module.`
3639
+ ].join("\n\n")
3640
+ );
3641
+ }
3642
+ function isNonNullable(x) {
3643
+ return x != null;
3644
+ }
2751
3645
  // Annotate the CommonJS export names for ESM import in node:
2752
3646
  0 && (module.exports = {
2753
3647
  reactRouter