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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vite.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v7.1.5
2
+ * @react-router/dev v7.2.0-pre.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -52,8 +52,10 @@ var fse = __toESM(require("fs-extra"));
52
52
  var babel = __toESM(require("@babel/core"));
53
53
  var import_react_router2 = require("react-router");
54
54
  var import_es_module_lexer = require("es-module-lexer");
55
+ var import_pick3 = __toESM(require("lodash/pick"));
55
56
  var import_jsesc = __toESM(require("jsesc"));
56
57
  var import_picocolors3 = __toESM(require("picocolors"));
58
+ var import_kebabCase = __toESM(require("lodash/kebabCase"));
57
59
 
58
60
  // typegen/index.ts
59
61
  var import_node_fs2 = __toESM(require("fs"));
@@ -270,6 +272,13 @@ var detectPackageManager = () => {
270
272
 
271
273
  // config/config.ts
272
274
  var excludedConfigPresetKeys = ["presets"];
275
+ var branchRouteProperties = [
276
+ "id",
277
+ "path",
278
+ "file",
279
+ "index"
280
+ ];
281
+ var configRouteToBranchRoute = (configRoute) => (0, import_pick2.default)(configRoute, branchRouteProperties);
273
282
  var mergeReactRouterConfig = (...configs) => {
274
283
  let reducer = (configA, configB) => {
275
284
  let mergeRequired = (key) => configA[key] !== void 0 && configB[key] !== void 0;
@@ -443,7 +452,9 @@ async function resolveConfig({
443
452
  );
444
453
  }
445
454
  let future = {
446
- unstable_optimizeDeps: reactRouterUserConfig.future?.unstable_optimizeDeps ?? false
455
+ unstable_optimizeDeps: reactRouterUserConfig.future?.unstable_optimizeDeps ?? false,
456
+ unstable_splitRouteModules: reactRouterUserConfig.future?.unstable_splitRouteModules ?? false,
457
+ unstable_viteEnvironmentApi: reactRouterUserConfig.future?.unstable_viteEnvironmentApi ?? false
447
458
  };
448
459
  let reactRouterConfig = deepFreeze({
449
460
  appDirectory,
@@ -1159,6 +1170,611 @@ function invalidDestructureError(name) {
1159
1170
  return new Error(`Cannot remove destructured export "${name}"`);
1160
1171
  }
1161
1172
 
1173
+ // vite/cache.ts
1174
+ function getOrSetFromCache(cache, key, version, getValue) {
1175
+ if (!cache) {
1176
+ return getValue();
1177
+ }
1178
+ let entry = cache.get(key);
1179
+ if (entry?.version === version) {
1180
+ return entry.value;
1181
+ }
1182
+ let value = getValue();
1183
+ let newEntry = { value, version };
1184
+ cache.set(key, newEntry);
1185
+ return value;
1186
+ }
1187
+
1188
+ // vite/route-chunks.ts
1189
+ function codeToAst(code, cache, cacheKey) {
1190
+ return structuredClone(
1191
+ getOrSetFromCache(
1192
+ cache,
1193
+ `${cacheKey}::codeToAst`,
1194
+ code,
1195
+ () => (0, import_parser.parse)(code, { sourceType: "module" })
1196
+ )
1197
+ );
1198
+ }
1199
+ function assertNodePath(path7) {
1200
+ invariant(
1201
+ path7 && !Array.isArray(path7),
1202
+ `Expected a Path, but got ${Array.isArray(path7) ? "an array" : path7}`
1203
+ );
1204
+ }
1205
+ function assertNodePathIsStatement(path7) {
1206
+ invariant(
1207
+ path7 && !Array.isArray(path7) && t.isStatement(path7.node),
1208
+ `Expected a Statement path, but got ${Array.isArray(path7) ? "an array" : path7?.node?.type}`
1209
+ );
1210
+ }
1211
+ function assertNodePathIsVariableDeclarator(path7) {
1212
+ invariant(
1213
+ path7 && !Array.isArray(path7) && t.isVariableDeclarator(path7.node),
1214
+ `Expected an Identifier path, but got ${Array.isArray(path7) ? "an array" : path7?.node?.type}`
1215
+ );
1216
+ }
1217
+ function assertNodePathIsPattern(path7) {
1218
+ invariant(
1219
+ path7 && !Array.isArray(path7) && t.isPattern(path7.node),
1220
+ `Expected a Pattern path, but got ${Array.isArray(path7) ? "an array" : path7?.node?.type}`
1221
+ );
1222
+ }
1223
+ function getExportDependencies(code, cache, cacheKey) {
1224
+ return getOrSetFromCache(
1225
+ cache,
1226
+ `${cacheKey}::getExportDependencies`,
1227
+ code,
1228
+ () => {
1229
+ let exportDependencies = /* @__PURE__ */ new Map();
1230
+ let ast = codeToAst(code, cache, cacheKey);
1231
+ function handleExport(exportName, exportPath, identifiersPath = exportPath) {
1232
+ let identifiers = getDependentIdentifiersForPath(identifiersPath);
1233
+ let topLevelStatements = /* @__PURE__ */ new Set([
1234
+ exportPath.node,
1235
+ ...getTopLevelStatementsForPaths(identifiers)
1236
+ ]);
1237
+ let topLevelNonModuleStatements = new Set(
1238
+ Array.from(topLevelStatements).filter(
1239
+ (statement) => !t.isImportDeclaration(statement) && !t.isExportDeclaration(statement)
1240
+ )
1241
+ );
1242
+ let importedIdentifierNames = /* @__PURE__ */ new Set();
1243
+ for (let identifier of identifiers) {
1244
+ if (identifier.parentPath.parentPath?.isImportDeclaration()) {
1245
+ importedIdentifierNames.add(identifier.node.name);
1246
+ }
1247
+ }
1248
+ let exportedVariableDeclarators = /* @__PURE__ */ new Set();
1249
+ for (let identifier of identifiers) {
1250
+ if (identifier.parentPath.isVariableDeclarator() && identifier.parentPath.parentPath.parentPath?.isExportNamedDeclaration()) {
1251
+ exportedVariableDeclarators.add(identifier.parentPath.node);
1252
+ continue;
1253
+ }
1254
+ let isWithinExportDestructuring = Boolean(
1255
+ identifier.findParent(
1256
+ (path7) => Boolean(
1257
+ path7.isPattern() && path7.parentPath?.isVariableDeclarator() && path7.parentPath.parentPath?.parentPath?.isExportNamedDeclaration()
1258
+ )
1259
+ )
1260
+ );
1261
+ if (isWithinExportDestructuring) {
1262
+ let currentPath = identifier;
1263
+ while (currentPath) {
1264
+ if (
1265
+ // Check the identifier is within a variable declaration, and if
1266
+ // so, ensure we're on the left-hand side of the expression
1267
+ // since these identifiers are what make up the export names,
1268
+ // e.g. export const { foo } = { foo: bar }; should pick up
1269
+ // `foo` but not `bar`.
1270
+ currentPath.parentPath?.isVariableDeclarator() && currentPath.parentKey === "id"
1271
+ ) {
1272
+ exportedVariableDeclarators.add(currentPath.parentPath.node);
1273
+ break;
1274
+ }
1275
+ currentPath = currentPath.parentPath;
1276
+ }
1277
+ }
1278
+ }
1279
+ let dependencies = {
1280
+ topLevelStatements,
1281
+ topLevelNonModuleStatements,
1282
+ importedIdentifierNames,
1283
+ exportedVariableDeclarators
1284
+ };
1285
+ exportDependencies.set(exportName, dependencies);
1286
+ }
1287
+ traverse(ast, {
1288
+ ExportDeclaration(exportPath) {
1289
+ let { node } = exportPath;
1290
+ if (t.isExportAllDeclaration(node)) {
1291
+ return;
1292
+ }
1293
+ if (t.isExportDefaultDeclaration(node)) {
1294
+ handleExport("default", exportPath);
1295
+ return;
1296
+ }
1297
+ let { declaration } = node;
1298
+ if (t.isVariableDeclaration(declaration)) {
1299
+ let { declarations } = declaration;
1300
+ for (let i = 0; i < declarations.length; i++) {
1301
+ let declarator = declarations[i];
1302
+ if (t.isIdentifier(declarator.id)) {
1303
+ let declaratorPath = exportPath.get(
1304
+ `declaration.declarations.${i}`
1305
+ );
1306
+ assertNodePathIsVariableDeclarator(declaratorPath);
1307
+ handleExport(declarator.id.name, exportPath, declaratorPath);
1308
+ continue;
1309
+ }
1310
+ if (t.isPattern(declarator.id)) {
1311
+ let exportedPatternPath = exportPath.get(
1312
+ `declaration.declarations.${i}.id`
1313
+ );
1314
+ assertNodePathIsPattern(exportedPatternPath);
1315
+ let identifiers = getIdentifiersForPatternPath(exportedPatternPath);
1316
+ for (let identifier of identifiers) {
1317
+ handleExport(identifier.node.name, exportPath, identifier);
1318
+ }
1319
+ }
1320
+ }
1321
+ return;
1322
+ }
1323
+ if (t.isFunctionDeclaration(declaration) || t.isClassDeclaration(declaration)) {
1324
+ invariant(
1325
+ declaration.id,
1326
+ "Expected exported function or class declaration to have a name when not the default export"
1327
+ );
1328
+ handleExport(declaration.id.name, exportPath);
1329
+ return;
1330
+ }
1331
+ if (t.isExportNamedDeclaration(node)) {
1332
+ for (let specifier of node.specifiers) {
1333
+ if (t.isIdentifier(specifier.exported)) {
1334
+ let name = specifier.exported.name;
1335
+ let specifierPath = exportPath.get("specifiers").find((path7) => path7.node === specifier);
1336
+ invariant(
1337
+ specifierPath,
1338
+ `Expected to find specifier path for ${name}`
1339
+ );
1340
+ handleExport(name, exportPath, specifierPath);
1341
+ }
1342
+ }
1343
+ return;
1344
+ }
1345
+ throw new Error(`Unknown export node type: ${node.type}`);
1346
+ }
1347
+ });
1348
+ return exportDependencies;
1349
+ }
1350
+ );
1351
+ }
1352
+ function getDependentIdentifiersForPath(path7, state) {
1353
+ let { visited, identifiers } = state ?? {
1354
+ visited: /* @__PURE__ */ new Set(),
1355
+ identifiers: /* @__PURE__ */ new Set()
1356
+ };
1357
+ if (visited.has(path7)) {
1358
+ return identifiers;
1359
+ }
1360
+ visited.add(path7);
1361
+ path7.traverse({
1362
+ Identifier(path8) {
1363
+ if (identifiers.has(path8)) {
1364
+ return;
1365
+ }
1366
+ identifiers.add(path8);
1367
+ let binding = path8.scope.getBinding(path8.node.name);
1368
+ if (!binding) {
1369
+ return;
1370
+ }
1371
+ getDependentIdentifiersForPath(binding.path, { visited, identifiers });
1372
+ for (let reference of binding.referencePaths) {
1373
+ if (reference.isExportNamedDeclaration()) {
1374
+ continue;
1375
+ }
1376
+ getDependentIdentifiersForPath(reference, {
1377
+ visited,
1378
+ identifiers
1379
+ });
1380
+ }
1381
+ for (let constantViolation of binding.constantViolations) {
1382
+ getDependentIdentifiersForPath(constantViolation, {
1383
+ visited,
1384
+ identifiers
1385
+ });
1386
+ }
1387
+ }
1388
+ });
1389
+ let topLevelStatement = getTopLevelStatementPathForPath(path7);
1390
+ let withinImportStatement = topLevelStatement.isImportDeclaration();
1391
+ let withinExportStatement = topLevelStatement.isExportDeclaration();
1392
+ if (!withinImportStatement && !withinExportStatement) {
1393
+ getDependentIdentifiersForPath(topLevelStatement, {
1394
+ visited,
1395
+ identifiers
1396
+ });
1397
+ }
1398
+ if (withinExportStatement && path7.isIdentifier() && (t.isPattern(path7.parentPath.node) || // [foo]
1399
+ t.isPattern(path7.parentPath.parentPath?.node))) {
1400
+ let variableDeclarator = path7.findParent((p) => p.isVariableDeclarator());
1401
+ assertNodePath(variableDeclarator);
1402
+ getDependentIdentifiersForPath(variableDeclarator, {
1403
+ visited,
1404
+ identifiers
1405
+ });
1406
+ }
1407
+ return identifiers;
1408
+ }
1409
+ function getTopLevelStatementPathForPath(path7) {
1410
+ let ancestry = path7.getAncestry();
1411
+ let topLevelStatement = ancestry[ancestry.length - 2];
1412
+ assertNodePathIsStatement(topLevelStatement);
1413
+ return topLevelStatement;
1414
+ }
1415
+ function getTopLevelStatementsForPaths(paths) {
1416
+ let topLevelStatements = /* @__PURE__ */ new Set();
1417
+ for (let path7 of paths) {
1418
+ let topLevelStatement = getTopLevelStatementPathForPath(path7);
1419
+ topLevelStatements.add(topLevelStatement.node);
1420
+ }
1421
+ return topLevelStatements;
1422
+ }
1423
+ function getIdentifiersForPatternPath(patternPath, identifiers = /* @__PURE__ */ new Set()) {
1424
+ function walk(currentPath) {
1425
+ if (currentPath.isIdentifier()) {
1426
+ identifiers.add(currentPath);
1427
+ return;
1428
+ }
1429
+ if (currentPath.isObjectPattern()) {
1430
+ let { properties } = currentPath.node;
1431
+ for (let i = 0; i < properties.length; i++) {
1432
+ const property = properties[i];
1433
+ if (t.isObjectProperty(property)) {
1434
+ let valuePath = currentPath.get(`properties.${i}.value`);
1435
+ assertNodePath(valuePath);
1436
+ walk(valuePath);
1437
+ } else if (t.isRestElement(property)) {
1438
+ let argumentPath = currentPath.get(`properties.${i}.argument`);
1439
+ assertNodePath(argumentPath);
1440
+ walk(argumentPath);
1441
+ }
1442
+ }
1443
+ } else if (currentPath.isArrayPattern()) {
1444
+ let { elements } = currentPath.node;
1445
+ for (let i = 0; i < elements.length; i++) {
1446
+ const element = elements[i];
1447
+ if (element) {
1448
+ let elementPath = currentPath.get(`elements.${i}`);
1449
+ assertNodePath(elementPath);
1450
+ walk(elementPath);
1451
+ }
1452
+ }
1453
+ } else if (currentPath.isRestElement()) {
1454
+ let argumentPath = currentPath.get("argument");
1455
+ assertNodePath(argumentPath);
1456
+ walk(argumentPath);
1457
+ }
1458
+ }
1459
+ walk(patternPath);
1460
+ return identifiers;
1461
+ }
1462
+ var getExportedName = (exported) => {
1463
+ return t.isIdentifier(exported) ? exported.name : exported.value;
1464
+ };
1465
+ function setsIntersect(set1, set2) {
1466
+ let smallerSet = set1;
1467
+ let largerSet = set2;
1468
+ if (set1.size > set2.size) {
1469
+ smallerSet = set2;
1470
+ largerSet = set1;
1471
+ }
1472
+ for (let element of smallerSet) {
1473
+ if (largerSet.has(element)) {
1474
+ return true;
1475
+ }
1476
+ }
1477
+ return false;
1478
+ }
1479
+ function hasChunkableExport(code, exportName, cache, cacheKey) {
1480
+ return getOrSetFromCache(
1481
+ cache,
1482
+ `${cacheKey}::hasChunkableExport::${exportName}`,
1483
+ code,
1484
+ () => {
1485
+ let exportDependencies = getExportDependencies(code, cache, cacheKey);
1486
+ let dependencies = exportDependencies.get(exportName);
1487
+ if (!dependencies) {
1488
+ return false;
1489
+ }
1490
+ for (let [currentExportName, currentDependencies] of exportDependencies) {
1491
+ if (currentExportName === exportName) {
1492
+ continue;
1493
+ }
1494
+ if (setsIntersect(
1495
+ currentDependencies.topLevelNonModuleStatements,
1496
+ dependencies.topLevelNonModuleStatements
1497
+ )) {
1498
+ return false;
1499
+ }
1500
+ }
1501
+ if (dependencies.exportedVariableDeclarators.size > 1) {
1502
+ return false;
1503
+ }
1504
+ if (dependencies.exportedVariableDeclarators.size > 0) {
1505
+ for (let [
1506
+ currentExportName,
1507
+ currentDependencies
1508
+ ] of exportDependencies) {
1509
+ if (currentExportName === exportName) {
1510
+ continue;
1511
+ }
1512
+ if (setsIntersect(
1513
+ currentDependencies.exportedVariableDeclarators,
1514
+ dependencies.exportedVariableDeclarators
1515
+ )) {
1516
+ return false;
1517
+ }
1518
+ }
1519
+ }
1520
+ return true;
1521
+ }
1522
+ );
1523
+ }
1524
+ function getChunkedExport(code, exportName, generateOptions = {}, cache, cacheKey) {
1525
+ return getOrSetFromCache(
1526
+ cache,
1527
+ `${cacheKey}::getChunkedExport::${exportName}::${JSON.stringify(
1528
+ generateOptions
1529
+ )}`,
1530
+ code,
1531
+ () => {
1532
+ if (!hasChunkableExport(code, exportName, cache, cacheKey)) {
1533
+ return void 0;
1534
+ }
1535
+ let exportDependencies = getExportDependencies(code, cache, cacheKey);
1536
+ let dependencies = exportDependencies.get(exportName);
1537
+ invariant(dependencies, "Expected export to have dependencies");
1538
+ let topLevelStatementsArray = Array.from(dependencies.topLevelStatements);
1539
+ let exportedVariableDeclaratorsArray = Array.from(
1540
+ dependencies.exportedVariableDeclarators
1541
+ );
1542
+ let ast = codeToAst(code, cache, cacheKey);
1543
+ ast.program.body = ast.program.body.filter(
1544
+ (node) => topLevelStatementsArray.some(
1545
+ (statement) => t.isNodesEquivalent(node, statement)
1546
+ )
1547
+ ).map((node) => {
1548
+ if (!t.isImportDeclaration(node)) {
1549
+ return node;
1550
+ }
1551
+ if (dependencies.importedIdentifierNames.size === 0) {
1552
+ return null;
1553
+ }
1554
+ node.specifiers = node.specifiers.filter(
1555
+ (specifier) => dependencies.importedIdentifierNames.has(specifier.local.name)
1556
+ );
1557
+ invariant(
1558
+ node.specifiers.length > 0,
1559
+ "Expected import statement to have used specifiers"
1560
+ );
1561
+ return node;
1562
+ }).map((node) => {
1563
+ if (!t.isExportDeclaration(node)) {
1564
+ return node;
1565
+ }
1566
+ if (t.isExportAllDeclaration(node)) {
1567
+ return null;
1568
+ }
1569
+ if (t.isExportDefaultDeclaration(node)) {
1570
+ return exportName === "default" ? node : null;
1571
+ }
1572
+ let { declaration } = node;
1573
+ if (t.isVariableDeclaration(declaration)) {
1574
+ declaration.declarations = declaration.declarations.filter(
1575
+ (node2) => exportedVariableDeclaratorsArray.some(
1576
+ (declarator) => t.isNodesEquivalent(node2, declarator)
1577
+ )
1578
+ );
1579
+ if (declaration.declarations.length === 0) {
1580
+ return null;
1581
+ }
1582
+ return node;
1583
+ }
1584
+ if (t.isFunctionDeclaration(node.declaration) || t.isClassDeclaration(node.declaration)) {
1585
+ return node.declaration.id?.name === exportName ? node : null;
1586
+ }
1587
+ if (t.isExportNamedDeclaration(node)) {
1588
+ if (node.specifiers.length === 0) {
1589
+ return null;
1590
+ }
1591
+ node.specifiers = node.specifiers.filter(
1592
+ (specifier) => getExportedName(specifier.exported) === exportName
1593
+ );
1594
+ if (node.specifiers.length === 0) {
1595
+ return null;
1596
+ }
1597
+ return node;
1598
+ }
1599
+ throw new Error(`Unknown export node type: ${node.type}`);
1600
+ }).filter((node) => node !== null);
1601
+ return generate2(ast, generateOptions);
1602
+ }
1603
+ );
1604
+ }
1605
+ function omitChunkedExports(code, exportNames, generateOptions = {}, cache, cacheKey) {
1606
+ return getOrSetFromCache(
1607
+ cache,
1608
+ `${cacheKey}::omitChunkedExports::${exportNames.join(
1609
+ ","
1610
+ )}::${JSON.stringify(generateOptions)}`,
1611
+ code,
1612
+ () => {
1613
+ const isChunkable = (exportName) => hasChunkableExport(code, exportName, cache, cacheKey);
1614
+ const isOmitted = (exportName) => exportNames.includes(exportName) && isChunkable(exportName);
1615
+ const isRetained = (exportName) => !isOmitted(exportName);
1616
+ let exportDependencies = getExportDependencies(code, cache, cacheKey);
1617
+ let allExportNames = Array.from(exportDependencies.keys());
1618
+ let omittedExportNames = allExportNames.filter(isOmitted);
1619
+ let retainedExportNames = allExportNames.filter(isRetained);
1620
+ let omittedStatements = /* @__PURE__ */ new Set();
1621
+ let omittedExportedVariableDeclarators = /* @__PURE__ */ new Set();
1622
+ for (let omittedExportName of omittedExportNames) {
1623
+ let dependencies = exportDependencies.get(omittedExportName);
1624
+ invariant(
1625
+ dependencies,
1626
+ `Expected dependencies for ${omittedExportName}`
1627
+ );
1628
+ for (let statement of dependencies.topLevelNonModuleStatements) {
1629
+ omittedStatements.add(statement);
1630
+ }
1631
+ for (let declarator of dependencies.exportedVariableDeclarators) {
1632
+ omittedExportedVariableDeclarators.add(declarator);
1633
+ }
1634
+ }
1635
+ let ast = codeToAst(code, cache, cacheKey);
1636
+ let omittedStatementsArray = Array.from(omittedStatements);
1637
+ let omittedExportedVariableDeclaratorsArray = Array.from(
1638
+ omittedExportedVariableDeclarators
1639
+ );
1640
+ ast.program.body = ast.program.body.filter(
1641
+ (node) => omittedStatementsArray.every(
1642
+ (statement) => !t.isNodesEquivalent(node, statement)
1643
+ )
1644
+ ).map((node) => {
1645
+ if (!t.isImportDeclaration(node)) {
1646
+ return node;
1647
+ }
1648
+ if (node.specifiers.length === 0) {
1649
+ return node;
1650
+ }
1651
+ node.specifiers = node.specifiers.filter((specifier) => {
1652
+ let importedName = specifier.local.name;
1653
+ for (let retainedExportName of retainedExportNames) {
1654
+ let dependencies = exportDependencies.get(retainedExportName);
1655
+ if (dependencies?.importedIdentifierNames?.has(importedName)) {
1656
+ return true;
1657
+ }
1658
+ }
1659
+ for (let omittedExportName of omittedExportNames) {
1660
+ let dependencies = exportDependencies.get(omittedExportName);
1661
+ if (dependencies?.importedIdentifierNames?.has(importedName)) {
1662
+ return false;
1663
+ }
1664
+ }
1665
+ return true;
1666
+ });
1667
+ if (node.specifiers.length === 0) {
1668
+ return null;
1669
+ }
1670
+ return node;
1671
+ }).map((node) => {
1672
+ if (!t.isExportDeclaration(node)) {
1673
+ return node;
1674
+ }
1675
+ if (t.isExportAllDeclaration(node)) {
1676
+ return node;
1677
+ }
1678
+ if (t.isExportDefaultDeclaration(node)) {
1679
+ return isOmitted("default") ? null : node;
1680
+ }
1681
+ if (t.isVariableDeclaration(node.declaration)) {
1682
+ node.declaration.declarations = node.declaration.declarations.filter(
1683
+ (node2) => omittedExportedVariableDeclaratorsArray.every(
1684
+ (declarator) => !t.isNodesEquivalent(node2, declarator)
1685
+ )
1686
+ );
1687
+ if (node.declaration.declarations.length === 0) {
1688
+ return null;
1689
+ }
1690
+ return node;
1691
+ }
1692
+ if (t.isFunctionDeclaration(node.declaration) || t.isClassDeclaration(node.declaration)) {
1693
+ invariant(
1694
+ node.declaration.id,
1695
+ "Expected exported function or class declaration to have a name when not the default export"
1696
+ );
1697
+ return isOmitted(node.declaration.id.name) ? null : node;
1698
+ }
1699
+ if (t.isExportNamedDeclaration(node)) {
1700
+ if (node.specifiers.length === 0) {
1701
+ return node;
1702
+ }
1703
+ node.specifiers = node.specifiers.filter((specifier) => {
1704
+ const exportedName = getExportedName(specifier.exported);
1705
+ return !isOmitted(exportedName);
1706
+ });
1707
+ if (node.specifiers.length === 0) {
1708
+ return null;
1709
+ }
1710
+ return node;
1711
+ }
1712
+ throw new Error(`Unknown node type: ${node.type}`);
1713
+ }).filter((node) => node !== null);
1714
+ if (ast.program.body.length === 0) {
1715
+ return void 0;
1716
+ }
1717
+ return generate2(ast, generateOptions);
1718
+ }
1719
+ );
1720
+ }
1721
+ function detectRouteChunks(code, cache, cacheKey) {
1722
+ const hasRouteChunkByExportName = Object.fromEntries(
1723
+ routeChunkExportNames.map((exportName) => [
1724
+ exportName,
1725
+ hasChunkableExport(code, exportName, cache, cacheKey)
1726
+ ])
1727
+ );
1728
+ const chunkedExports = Object.entries(hasRouteChunkByExportName).filter(([, isChunked]) => isChunked).map(([exportName]) => exportName);
1729
+ const hasRouteChunks = chunkedExports.length > 0;
1730
+ return {
1731
+ hasRouteChunks,
1732
+ hasRouteChunkByExportName,
1733
+ chunkedExports
1734
+ };
1735
+ }
1736
+ var routeChunkExportNames = [
1737
+ "clientAction",
1738
+ "clientLoader",
1739
+ "HydrateFallback"
1740
+ ];
1741
+ var mainChunkName = "main";
1742
+ var routeChunkNames = ["main", ...routeChunkExportNames];
1743
+ function getRouteChunkCode(code, chunkName, cache, cacheKey) {
1744
+ if (chunkName === mainChunkName) {
1745
+ return omitChunkedExports(code, routeChunkExportNames, {}, cache, cacheKey);
1746
+ }
1747
+ return getChunkedExport(code, chunkName, {}, cache, cacheKey);
1748
+ }
1749
+ var routeChunkQueryStringPrefix = "?route-chunk=";
1750
+ var routeChunkQueryStrings = {
1751
+ main: `${routeChunkQueryStringPrefix}main`,
1752
+ clientAction: `${routeChunkQueryStringPrefix}clientAction`,
1753
+ clientLoader: `${routeChunkQueryStringPrefix}clientLoader`,
1754
+ HydrateFallback: `${routeChunkQueryStringPrefix}HydrateFallback`
1755
+ };
1756
+ function getRouteChunkModuleId(filePath, chunkName) {
1757
+ return `${filePath}${routeChunkQueryStrings[chunkName]}`;
1758
+ }
1759
+ function isRouteChunkModuleId(id) {
1760
+ return Object.values(routeChunkQueryStrings).some(
1761
+ (queryString) => id.endsWith(queryString)
1762
+ );
1763
+ }
1764
+ function isRouteChunkName(name) {
1765
+ return name === mainChunkName || routeChunkExportNames.includes(name);
1766
+ }
1767
+ function getRouteChunkNameFromModuleId(id) {
1768
+ if (!isRouteChunkModuleId(id)) {
1769
+ return null;
1770
+ }
1771
+ let chunkName = id.split(routeChunkQueryStringPrefix)[1].split("&")[0];
1772
+ if (!isRouteChunkName(chunkName)) {
1773
+ return null;
1774
+ }
1775
+ return chunkName;
1776
+ }
1777
+
1162
1778
  // vite/with-props.ts
1163
1779
  var import_dedent2 = __toESM(require("dedent"));
1164
1780
  var vmod = create("with-props");
@@ -1191,6 +1807,8 @@ var plugin = {
1191
1807
  return function Wrapped() {
1192
1808
  const props = {
1193
1809
  params: useParams(),
1810
+ loaderData: useLoaderData(),
1811
+ actionData: useActionData(),
1194
1812
  };
1195
1813
  return h(HydrateFallback, props);
1196
1814
  };
@@ -1298,8 +1916,34 @@ var CLIENT_ROUTE_EXPORTS = [
1298
1916
  "shouldRevalidate"
1299
1917
  ];
1300
1918
  var BUILD_CLIENT_ROUTE_QUERY_STRING = "?__react-router-build-client-route";
1919
+ var SSR_BUNDLE_PREFIX = "ssrBundle_";
1920
+ function isSeverBundleEnvironmentName(name) {
1921
+ return name.startsWith(SSR_BUNDLE_PREFIX);
1922
+ }
1923
+ function getServerEnvironmentEntries(record, buildManifest) {
1924
+ return Object.entries(record).filter(
1925
+ ([name]) => buildManifest.serverBundles ? isSeverBundleEnvironmentName(name) : name === "ssr"
1926
+ );
1927
+ }
1928
+ function getServerEnvironmentValues(record, buildManifest) {
1929
+ return getServerEnvironmentEntries(record, buildManifest).map(
1930
+ ([, value]) => value
1931
+ );
1932
+ }
1933
+ var isRouteEntryModuleId = (id) => {
1934
+ return id.endsWith(BUILD_CLIENT_ROUTE_QUERY_STRING);
1935
+ };
1936
+ var isRouteVirtualModule = (id) => {
1937
+ return isRouteEntryModuleId(id) || isRouteChunkModuleId(id);
1938
+ };
1301
1939
  var virtualHmrRuntime = create("hmr-runtime");
1302
1940
  var virtualInjectHmrRuntime = create("inject-hmr-runtime");
1941
+ var normalizeRelativeFilePath = (file, reactRouterConfig) => {
1942
+ let vite2 = getVite();
1943
+ let fullPath = path6.resolve(reactRouterConfig.appDirectory, file);
1944
+ let relativePath = path6.relative(reactRouterConfig.appDirectory, fullPath);
1945
+ return vite2.normalizePath(relativePath).split("?")[0];
1946
+ };
1303
1947
  var resolveRelativeRouteFilePath = (route, reactRouterConfig) => {
1304
1948
  let vite2 = getVite();
1305
1949
  let file = route.file;
@@ -1328,23 +1972,35 @@ var resolveChunk = (ctx, viteManifest, absoluteFilePath) => {
1328
1972
  let rootRelativeFilePath = vite2.normalizePath(
1329
1973
  path6.relative(ctx.rootDirectory, absoluteFilePath)
1330
1974
  );
1331
- let entryChunk = viteManifest[rootRelativeFilePath + BUILD_CLIENT_ROUTE_QUERY_STRING] ?? viteManifest[rootRelativeFilePath];
1975
+ let entryChunk = viteManifest[rootRelativeFilePath];
1332
1976
  if (!entryChunk) {
1333
- let knownManifestKeys = Object.keys(viteManifest).map((key) => '"' + key + '"').join(", ");
1334
- throw new Error(
1335
- `No manifest entry found for "${rootRelativeFilePath}". Known manifest keys: ${knownManifestKeys}`
1336
- );
1977
+ return void 0;
1337
1978
  }
1338
1979
  return entryChunk;
1339
1980
  };
1981
+ var getPublicModulePathForEntry = (ctx, viteManifest, entryFilePath) => {
1982
+ let entryChunk = resolveChunk(ctx, viteManifest, entryFilePath);
1983
+ return entryChunk ? `${ctx.publicPath}${entryChunk.file}` : void 0;
1984
+ };
1340
1985
  var getReactRouterManifestBuildAssets = (ctx, viteManifest, entryFilePath, prependedAssetFilePaths = []) => {
1341
1986
  let entryChunk = resolveChunk(ctx, viteManifest, entryFilePath);
1342
- let prependedAssetChunks = prependedAssetFilePaths.map(
1343
- (filePath) => resolveChunk(ctx, viteManifest, filePath)
1344
- );
1987
+ invariant(entryChunk, "Chunk not found");
1988
+ let prependedAssetChunks = prependedAssetFilePaths.map((filePath) => {
1989
+ let chunk = resolveChunk(ctx, viteManifest, filePath);
1990
+ invariant(chunk, "Chunk not found");
1991
+ return chunk;
1992
+ });
1993
+ let routeModuleChunks = routeChunkNames.map(
1994
+ (routeChunkName) => resolveChunk(
1995
+ ctx,
1996
+ viteManifest,
1997
+ getRouteChunkModuleId(entryFilePath.split("?")[0], routeChunkName)
1998
+ )
1999
+ ).filter(isNonNullable);
1345
2000
  let chunks = resolveDependantChunks(viteManifest, [
1346
2001
  ...prependedAssetChunks,
1347
- entryChunk
2002
+ entryChunk,
2003
+ ...routeModuleChunks
1348
2004
  ]);
1349
2005
  return {
1350
2006
  module: `${ctx.publicPath}${entryChunk.file}`,
@@ -1381,6 +2037,10 @@ var writeFileSafe = async (file, contents) => {
1381
2037
  await fse.ensureDir(path6.dirname(file));
1382
2038
  await fse.writeFile(file, contents);
1383
2039
  };
2040
+ var getExportNames = (code) => {
2041
+ let [, exportSpecifiers] = (0, import_es_module_lexer.parse)(code);
2042
+ return exportSpecifiers.map(({ n: name }) => name);
2043
+ };
1384
2044
  var getRouteManifestModuleExports = async (viteChildCompiler, ctx) => {
1385
2045
  let entries = await Promise.all(
1386
2046
  Object.entries(ctx.reactRouterConfig.routes).map(async ([key, route]) => {
@@ -1394,7 +2054,7 @@ var getRouteManifestModuleExports = async (viteChildCompiler, ctx) => {
1394
2054
  );
1395
2055
  return Object.fromEntries(entries);
1396
2056
  };
1397
- var getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
2057
+ var compileRouteFile = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
1398
2058
  if (!viteChildCompiler) {
1399
2059
  throw new Error("Vite child compiler not found");
1400
2060
  }
@@ -1414,20 +2074,38 @@ var getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteF
1414
2074
  moduleGraph.ensureEntryFromUrl(url2, ssr)
1415
2075
  ]);
1416
2076
  let transformed = await pluginContainer.transform(code, id, { ssr });
1417
- let [, exports2] = (0, import_es_module_lexer.parse)(transformed.code);
1418
- let exportNames = exports2.map((e) => e.n);
1419
- return exportNames;
2077
+ return transformed.code;
2078
+ };
2079
+ var getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
2080
+ if (!viteChildCompiler) {
2081
+ throw new Error("Vite child compiler not found");
2082
+ }
2083
+ let code = await compileRouteFile(
2084
+ viteChildCompiler,
2085
+ ctx,
2086
+ routeFile,
2087
+ readRouteFile
2088
+ );
2089
+ return getExportNames(code);
1420
2090
  };
1421
- var getServerBundleBuildConfig = (viteUserConfig) => {
1422
- if (!("__reactRouterServerBundleBuildConfig" in viteUserConfig) || !viteUserConfig.__reactRouterServerBundleBuildConfig) {
2091
+ var resolveEnvironmentBuildContext = ({
2092
+ viteCommand,
2093
+ viteUserConfig
2094
+ }) => {
2095
+ if (!("__reactRouterEnvironmentBuildContext" in viteUserConfig) || !viteUserConfig.__reactRouterEnvironmentBuildContext) {
1423
2096
  return null;
1424
2097
  }
1425
- return viteUserConfig.__reactRouterServerBundleBuildConfig;
2098
+ let buildContext = viteUserConfig.__reactRouterEnvironmentBuildContext;
2099
+ let resolvedBuildContext = {
2100
+ name: buildContext.name,
2101
+ options: buildContext.resolveOptions({ viteUserConfig })
2102
+ };
2103
+ return resolvedBuildContext;
1426
2104
  };
1427
- var getServerBuildDirectory = (ctx) => path6.join(
2105
+ var getServerBuildDirectory = (ctx, { serverBundleId } = {}) => path6.join(
1428
2106
  ctx.reactRouterConfig.buildDirectory,
1429
2107
  "server",
1430
- ...ctx.serverBundleBuildConfig ? [ctx.serverBundleBuildConfig.serverBundleId] : []
2108
+ ...serverBundleId ? [serverBundleId] : []
1431
2109
  );
1432
2110
  var getClientBuildDirectory = (reactRouterConfig) => path6.join(reactRouterConfig.buildDirectory, "client");
1433
2111
  var defaultEntriesDir = path6.resolve(
@@ -1445,8 +2123,10 @@ var reactRouterVitePlugin = () => {
1445
2123
  let viteUserConfig;
1446
2124
  let viteConfigEnv;
1447
2125
  let viteConfig;
2126
+ let buildManifest;
1448
2127
  let cssModulesManifest = {};
1449
2128
  let viteChildCompiler = null;
2129
+ let cache = /* @__PURE__ */ new Map();
1450
2130
  let reactRouterConfigLoader;
1451
2131
  let typegenWatcherPromise;
1452
2132
  let logger;
@@ -1478,36 +2158,37 @@ var reactRouterVitePlugin = () => {
1478
2158
  process.exit(1);
1479
2159
  }
1480
2160
  let viteManifestEnabled = viteUserConfig.build?.manifest === true;
1481
- let ssrBuildCtx = viteConfigEnv.isSsrBuild && viteCommand === "build" ? {
1482
- isSsrBuild: true,
1483
- getReactRouterServerManifest: async () => (await generateReactRouterManifestsForBuild()).reactRouterServerManifest,
1484
- serverBundleBuildConfig: getServerBundleBuildConfig(viteUserConfig)
1485
- } : { isSsrBuild: false };
2161
+ let environmentBuildContext = viteCommand === "build" ? resolveEnvironmentBuildContext({ viteCommand, viteUserConfig }) : null;
1486
2162
  firstLoad = false;
1487
2163
  ctx = {
2164
+ environmentBuildContext,
1488
2165
  reactRouterConfig,
1489
2166
  rootDirectory,
1490
2167
  entryClientFilePath,
1491
2168
  entryServerFilePath,
1492
2169
  publicPath,
1493
- viteManifestEnabled,
1494
- ...ssrBuildCtx
2170
+ viteManifestEnabled
1495
2171
  };
1496
2172
  };
1497
2173
  let pluginIndex = (pluginName) => {
1498
2174
  invariant(viteConfig);
1499
2175
  return viteConfig.plugins.findIndex((plugin2) => plugin2.name === pluginName);
1500
2176
  };
1501
- let getServerEntry = async () => {
2177
+ let getServerEntry = async ({ routeIds }) => {
1502
2178
  invariant(viteConfig, "viteconfig required to generate the server entry");
1503
- let routes = ctx.serverBundleBuildConfig ? (
2179
+ let routes = routeIds ? (
1504
2180
  // For server bundle builds, the server build should only import the
1505
2181
  // routes for this bundle rather than importing all routes
1506
- ctx.serverBundleBuildConfig.routes
2182
+ (0, import_pick3.default)(ctx.reactRouterConfig.routes, routeIds)
1507
2183
  ) : (
1508
2184
  // Otherwise, all routes are imported as usual
1509
2185
  ctx.reactRouterConfig.routes
1510
2186
  );
2187
+ let prerenderPaths = await getPrerenderPaths(
2188
+ ctx.reactRouterConfig.prerender,
2189
+ ctx.reactRouterConfig.ssr,
2190
+ routes
2191
+ );
1511
2192
  return `
1512
2193
  import * as entryServer from ${JSON.stringify(
1513
2194
  resolveFileUrl(ctx, ctx.entryServerFilePath)
@@ -1522,7 +2203,7 @@ var reactRouterVitePlugin = () => {
1522
2203
  )};`;
1523
2204
  }).join("\n")}
1524
2205
  export { default as assets } from ${JSON.stringify(
1525
- virtual.serverManifest.id
2206
+ `${virtual.serverManifest.id}${routeIds ? `?route-ids=${routeIds.join(",")}` : ""}`
1526
2207
  )};
1527
2208
  export const assetsBuildDirectory = ${JSON.stringify(
1528
2209
  path6.relative(
@@ -1532,7 +2213,9 @@ var reactRouterVitePlugin = () => {
1532
2213
  )};
1533
2214
  export const basename = ${JSON.stringify(ctx.reactRouterConfig.basename)};
1534
2215
  export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
1535
- export const isSpaMode = ${!ctx.reactRouterConfig.ssr && ctx.reactRouterConfig.prerender == null};
2216
+ export const ssr = ${ctx.reactRouterConfig.ssr};
2217
+ export const isSpaMode = ${isSpaModeEnabled(ctx.reactRouterConfig)};
2218
+ export const prerender = ${JSON.stringify(prerenderPaths)};
1536
2219
  export const publicPath = ${JSON.stringify(ctx.publicPath)};
1537
2220
  export const entry = { module: entryServer };
1538
2221
  export const routes = {
@@ -1570,7 +2253,9 @@ var reactRouterVitePlugin = () => {
1570
2253
  );
1571
2254
  return /* @__PURE__ */ new Set([...cssUrlPaths, ...chunkAssetPaths]);
1572
2255
  };
1573
- let generateReactRouterManifestsForBuild = async () => {
2256
+ let generateReactRouterManifestsForBuild = async ({
2257
+ routeIds
2258
+ }) => {
1574
2259
  invariant(viteConfig);
1575
2260
  let viteManifest = await loadViteManifest(
1576
2261
  getClientBuildDirectory(ctx.reactRouterConfig)
@@ -1586,13 +2271,31 @@ var reactRouterVitePlugin = () => {
1586
2271
  viteChildCompiler,
1587
2272
  ctx
1588
2273
  );
1589
- for (let [key, route] of Object.entries(ctx.reactRouterConfig.routes)) {
1590
- let routeFilePath = path6.join(
1591
- ctx.reactRouterConfig.appDirectory,
1592
- route.file
1593
- );
1594
- let sourceExports = routeManifestExports[key];
2274
+ let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
2275
+ for (let route of Object.values(ctx.reactRouterConfig.routes)) {
2276
+ let routeFile = path6.join(ctx.reactRouterConfig.appDirectory, route.file);
2277
+ let sourceExports = routeManifestExports[route.id];
1595
2278
  let isRootRoute = route.parentId === void 0;
2279
+ let hasClientAction = sourceExports.includes("clientAction");
2280
+ let hasClientLoader = sourceExports.includes("clientLoader");
2281
+ let hasHydrateFallback = sourceExports.includes("HydrateFallback");
2282
+ let { hasRouteChunkByExportName } = await detectRouteChunksIfEnabled(
2283
+ cache,
2284
+ ctx,
2285
+ routeFile,
2286
+ { routeFile, viteChildCompiler }
2287
+ );
2288
+ if (enforceSplitRouteModules) {
2289
+ validateRouteChunks({
2290
+ ctx,
2291
+ id: route.file,
2292
+ valid: {
2293
+ clientAction: !hasClientAction || hasRouteChunkByExportName.clientAction,
2294
+ clientLoader: !hasClientLoader || hasRouteChunkByExportName.clientLoader,
2295
+ HydrateFallback: !hasHydrateFallback || hasRouteChunkByExportName.HydrateFallback
2296
+ }
2297
+ });
2298
+ }
1596
2299
  let routeManifestEntry = {
1597
2300
  id: route.id,
1598
2301
  parentId: route.parentId,
@@ -1601,23 +2304,37 @@ var reactRouterVitePlugin = () => {
1601
2304
  caseSensitive: route.caseSensitive,
1602
2305
  hasAction: sourceExports.includes("action"),
1603
2306
  hasLoader: sourceExports.includes("loader"),
1604
- hasClientAction: sourceExports.includes("clientAction"),
1605
- hasClientLoader: sourceExports.includes("clientLoader"),
2307
+ hasClientAction,
2308
+ hasClientLoader,
1606
2309
  hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
1607
2310
  ...getReactRouterManifestBuildAssets(
1608
2311
  ctx,
1609
2312
  viteManifest,
1610
- routeFilePath,
2313
+ `${routeFile}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
1611
2314
  // If this is the root route, we also need to include assets from the
1612
2315
  // client entry file as this is a common way for consumers to import
1613
2316
  // global reset styles, etc.
1614
2317
  isRootRoute ? [ctx.entryClientFilePath] : []
1615
- )
2318
+ ),
2319
+ clientActionModule: hasRouteChunkByExportName.clientAction ? getPublicModulePathForEntry(
2320
+ ctx,
2321
+ viteManifest,
2322
+ getRouteChunkModuleId(routeFile, "clientAction")
2323
+ ) : void 0,
2324
+ clientLoaderModule: hasRouteChunkByExportName.clientLoader ? getPublicModulePathForEntry(
2325
+ ctx,
2326
+ viteManifest,
2327
+ getRouteChunkModuleId(routeFile, "clientLoader")
2328
+ ) : void 0,
2329
+ hydrateFallbackModule: hasRouteChunkByExportName.HydrateFallback ? getPublicModulePathForEntry(
2330
+ ctx,
2331
+ viteManifest,
2332
+ getRouteChunkModuleId(routeFile, "HydrateFallback")
2333
+ ) : void 0
1616
2334
  };
1617
- browserRoutes[key] = routeManifestEntry;
1618
- let serverBundleRoutes = ctx.serverBundleBuildConfig?.routes;
1619
- if (!serverBundleRoutes || serverBundleRoutes[key]) {
1620
- serverRoutes[key] = routeManifestEntry;
2335
+ browserRoutes[route.id] = routeManifestEntry;
2336
+ if (!routeIds || routeIds.includes(route.id)) {
2337
+ serverRoutes[route.id] = routeManifestEntry;
1621
2338
  }
1622
2339
  }
1623
2340
  let fingerprintedValues = { entry, routes: browserRoutes };
@@ -1653,25 +2370,52 @@ var reactRouterVitePlugin = () => {
1653
2370
  viteChildCompiler,
1654
2371
  ctx
1655
2372
  );
2373
+ let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
1656
2374
  for (let [key, route] of Object.entries(ctx.reactRouterConfig.routes)) {
2375
+ let routeFile = route.file;
1657
2376
  let sourceExports = routeManifestExports[key];
2377
+ let hasClientAction = sourceExports.includes("clientAction");
2378
+ let hasClientLoader = sourceExports.includes("clientLoader");
2379
+ let hasHydrateFallback = sourceExports.includes("HydrateFallback");
2380
+ let routeModulePath = combineURLs(
2381
+ ctx.publicPath,
2382
+ `${resolveFileUrl(
2383
+ ctx,
2384
+ resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
2385
+ )}`
2386
+ );
2387
+ if (enforceSplitRouteModules) {
2388
+ let { hasRouteChunkByExportName } = await detectRouteChunksIfEnabled(
2389
+ cache,
2390
+ ctx,
2391
+ routeFile,
2392
+ { routeFile, viteChildCompiler }
2393
+ );
2394
+ validateRouteChunks({
2395
+ ctx,
2396
+ id: route.file,
2397
+ valid: {
2398
+ clientAction: !hasClientAction || hasRouteChunkByExportName.clientAction,
2399
+ clientLoader: !hasClientLoader || hasRouteChunkByExportName.clientLoader,
2400
+ HydrateFallback: !hasHydrateFallback || hasRouteChunkByExportName.HydrateFallback
2401
+ }
2402
+ });
2403
+ }
1658
2404
  routes[key] = {
1659
2405
  id: route.id,
1660
2406
  parentId: route.parentId,
1661
2407
  path: route.path,
1662
2408
  index: route.index,
1663
2409
  caseSensitive: route.caseSensitive,
1664
- module: combineURLs(
1665
- ctx.publicPath,
1666
- resolveFileUrl(
1667
- ctx,
1668
- resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
1669
- )
1670
- ),
2410
+ module: routeModulePath,
2411
+ // Split route modules are a build-time optimization
2412
+ clientActionModule: void 0,
2413
+ clientLoaderModule: void 0,
2414
+ hydrateFallbackModule: void 0,
1671
2415
  hasAction: sourceExports.includes("action"),
1672
2416
  hasLoader: sourceExports.includes("loader"),
1673
- hasClientAction: sourceExports.includes("clientAction"),
1674
- hasClientLoader: sourceExports.includes("clientLoader"),
2417
+ hasClientAction,
2418
+ hasClientLoader,
1675
2419
  hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
1676
2420
  imports: []
1677
2421
  };
@@ -1704,14 +2448,6 @@ var reactRouterVitePlugin = () => {
1704
2448
  let viteClientConditions = [
1705
2449
  ...vite2.defaultClientConditions ?? []
1706
2450
  ];
1707
- let packageRoot = path6.dirname(
1708
- require.resolve("@react-router/dev/package.json")
1709
- );
1710
- let { moduleSyncEnabled } = await import(`file:///${path6.join(packageRoot, "module-sync-enabled/index.mjs")}`);
1711
- let viteServerConditions = [
1712
- ...vite2.defaultServerConditions ?? [],
1713
- ...moduleSyncEnabled ? ["module-sync"] : []
1714
- ];
1715
2451
  logger = vite2.createLogger(viteUserConfig.logLevel, {
1716
2452
  prefix: "[react-router]"
1717
2453
  });
@@ -1727,43 +2463,37 @@ var reactRouterVitePlugin = () => {
1727
2463
  watch: viteCommand === "serve"
1728
2464
  });
1729
2465
  await updatePluginContext();
2466
+ buildManifest = await getBuildManifest(ctx);
1730
2467
  Object.assign(
1731
2468
  process.env,
1732
2469
  vite2.loadEnv(
1733
2470
  viteConfigEnv.mode,
1734
- ctx.rootDirectory,
2471
+ viteUserConfig.envDir ?? ctx.rootDirectory,
1735
2472
  // We override default prefix of "VITE_" with a blank string since
1736
2473
  // we're targeting the server, so we want to load all environment
1737
2474
  // variables, not just those explicitly marked for the client
1738
2475
  ""
1739
2476
  )
1740
2477
  );
1741
- let baseRollupOptions = {
1742
- // Silence Rollup "use client" warnings
1743
- // Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
1744
- onwarn(warning, defaultHandler) {
1745
- if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
1746
- return;
1747
- }
1748
- if (viteUserConfig.build?.rollupOptions?.onwarn) {
1749
- viteUserConfig.build.rollupOptions.onwarn(
1750
- warning,
1751
- defaultHandler
1752
- );
1753
- } else {
1754
- defaultHandler(warning);
1755
- }
1756
- }
1757
- };
2478
+ let environments = await getEnvironmentsOptions(
2479
+ ctx,
2480
+ buildManifest,
2481
+ viteCommand,
2482
+ { viteUserConfig }
2483
+ );
2484
+ let serverEnvironment = getServerEnvironmentValues(
2485
+ environments,
2486
+ buildManifest
2487
+ )[0];
2488
+ invariant(serverEnvironment);
2489
+ let clientEnvironment = environments.client;
2490
+ invariant(clientEnvironment);
1758
2491
  return {
1759
2492
  __reactRouterPluginContext: ctx,
1760
2493
  appType: viteCommand === "serve" && viteConfigEnv.mode === "production" && ctx.reactRouterConfig.ssr === false ? "spa" : "custom",
1761
2494
  ssr: {
1762
- external: ssrExternals,
1763
- resolve: {
1764
- conditions: viteCommand === "build" ? viteServerConditions : ["development", ...viteServerConditions],
1765
- externalConditions: viteCommand === "build" ? viteServerConditions : ["development", ...viteServerConditions]
1766
- }
2495
+ external: serverEnvironment.resolve?.external,
2496
+ resolve: serverEnvironment.resolve
1767
2497
  },
1768
2498
  optimizeDeps: {
1769
2499
  entries: ctx.reactRouterConfig.future.unstable_optimizeDeps ? [
@@ -1812,57 +2542,41 @@ var reactRouterVitePlugin = () => {
1812
2542
  // will throw an error that the file is not allowed to be read.
1813
2543
  // https://vitejs.dev/config/server-options#server-fs-allow
1814
2544
  server: viteUserConfig.server?.fs?.allow ? { fs: { allow: defaultEntries } } : void 0,
1815
- // Vite config options for building
1816
- ...viteCommand === "build" ? {
2545
+ ...ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? {
2546
+ environments,
1817
2547
  build: {
1818
- cssMinify: viteUserConfig.build?.cssMinify ?? true,
1819
- ...!viteConfigEnv.isSsrBuild ? {
1820
- manifest: true,
1821
- outDir: getClientBuildDirectory(ctx.reactRouterConfig),
1822
- rollupOptions: {
1823
- ...baseRollupOptions,
1824
- preserveEntrySignatures: "exports-only",
1825
- input: [
1826
- ctx.entryClientFilePath,
1827
- ...Object.values(ctx.reactRouterConfig.routes).map(
1828
- (route) => `${path6.resolve(
1829
- ctx.reactRouterConfig.appDirectory,
1830
- route.file
1831
- )}${BUILD_CLIENT_ROUTE_QUERY_STRING}`
1832
- )
1833
- ]
1834
- }
1835
- } : {
1836
- // We move SSR-only assets to client assets. Note that the
1837
- // SSR build can also emit code-split JS files (e.g. by
1838
- // dynamic import) under the same assets directory
1839
- // regardless of "ssrEmitAssets" option, so we also need to
1840
- // keep these JS files have to be kept as-is.
1841
- ssrEmitAssets: true,
1842
- copyPublicDir: false,
1843
- // Assets in the public directory are only used by the client
1844
- manifest: true,
1845
- // We need the manifest to detect SSR-only assets
1846
- outDir: getServerBuildDirectory(ctx),
1847
- rollupOptions: {
1848
- ...baseRollupOptions,
1849
- preserveEntrySignatures: "exports-only",
1850
- input: viteUserConfig.build?.rollupOptions?.input ?? virtual.serverBuild.id,
1851
- output: {
1852
- entryFileNames: ctx.reactRouterConfig.serverBuildFile,
1853
- format: ctx.reactRouterConfig.serverModuleFormat
1854
- }
1855
- }
2548
+ // This isn't honored by the SSR environment config (which seems
2549
+ // to be a Vite bug?) so we set it here too.
2550
+ ssrEmitAssets: true
2551
+ },
2552
+ builder: {
2553
+ sharedConfigBuild: true,
2554
+ sharedPlugins: true,
2555
+ async buildApp(builder) {
2556
+ invariant(viteConfig);
2557
+ invariant(buildManifest);
2558
+ viteConfig.logger.info(
2559
+ "Using Vite Environment API (experimental)"
2560
+ );
2561
+ let { reactRouterConfig } = ctx;
2562
+ await cleanBuildDirectory(viteConfig, ctx);
2563
+ await builder.build(builder.environments.client);
2564
+ let serverEnvironments = getServerEnvironmentValues(
2565
+ builder.environments,
2566
+ buildManifest
2567
+ );
2568
+ await Promise.all(serverEnvironments.map(builder.build));
2569
+ await cleanViteManifests(environments, ctx);
2570
+ await reactRouterConfig.buildEnd?.({
2571
+ buildManifest,
2572
+ reactRouterConfig,
2573
+ viteConfig
2574
+ });
1856
2575
  }
1857
2576
  }
1858
- } : void 0,
1859
- // Vite config options for SPA preview mode
1860
- ...viteCommand === "serve" && ctx.reactRouterConfig.ssr === false ? {
1861
- build: {
1862
- manifest: true,
1863
- outDir: getClientBuildDirectory(ctx.reactRouterConfig)
1864
- }
1865
- } : void 0
2577
+ } : {
2578
+ build: ctx.environmentBuildContext?.options.build ?? (viteConfigEnv.isSsrBuild ? serverEnvironment.build : clientEnvironment.build)
2579
+ }
1866
2580
  };
1867
2581
  },
1868
2582
  async configResolved(resolvedViteConfig) {
@@ -1878,8 +2592,7 @@ var reactRouterVitePlugin = () => {
1878
2592
  let childCompilerConfigFile = await vite2.loadConfigFromFile(
1879
2593
  {
1880
2594
  command: viteConfig.command,
1881
- mode: viteConfig.mode,
1882
- isSsrBuild: ctx.isSsrBuild
2595
+ mode: viteConfig.mode
1883
2596
  },
1884
2597
  viteConfig.configFile
1885
2598
  );
@@ -2021,14 +2734,15 @@ var reactRouterVitePlugin = () => {
2021
2734
  // After the SSR build is finished, we inspect the Vite manifest for
2022
2735
  // the SSR build and move server-only assets to client assets directory
2023
2736
  async handler() {
2024
- if (!ctx.isSsrBuild) {
2737
+ let { future } = ctx.reactRouterConfig;
2738
+ if (future.unstable_viteEnvironmentApi ? this.environment.name === "client" : !viteConfigEnv.isSsrBuild) {
2025
2739
  return;
2026
2740
  }
2027
2741
  invariant(viteConfig);
2028
2742
  let clientBuildDirectory = getClientBuildDirectory(
2029
2743
  ctx.reactRouterConfig
2030
2744
  );
2031
- let serverBuildDirectory = getServerBuildDirectory(ctx);
2745
+ let serverBuildDirectory = future.unstable_viteEnvironmentApi ? this.environment.config?.build?.outDir : ctx.environmentBuildContext?.options.build?.outDir ?? getServerBuildDirectory(ctx);
2032
2746
  let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
2033
2747
  let ssrAssetPaths = getViteManifestAssetPaths(ssrViteManifest);
2034
2748
  let movedAssetPaths = [];
@@ -2062,7 +2776,7 @@ var reactRouterVitePlugin = () => {
2062
2776
  ].join("\n")
2063
2777
  );
2064
2778
  }
2065
- if (ctx.reactRouterConfig.prerender != null && ctx.reactRouterConfig.prerender !== false) {
2779
+ if (isPrerenderingEnabled(ctx.reactRouterConfig)) {
2066
2780
  await handlePrerender(
2067
2781
  viteConfig,
2068
2782
  ctx.reactRouterConfig,
@@ -2099,10 +2813,59 @@ var reactRouterVitePlugin = () => {
2099
2813
  await typegenWatcher?.close();
2100
2814
  }
2101
2815
  },
2816
+ {
2817
+ name: "react-router:route-chunks-index",
2818
+ // This plugin provides the route module "index" since route modules can
2819
+ // be chunked and may be made up of multiple smaller modules. This plugin
2820
+ // primarily ensures code is never duplicated across a route module and
2821
+ // its chunks. If we didn't have this plugin, any app that explicitly
2822
+ // imports a route module would result in duplicate code since the app
2823
+ // would contain code for both the unprocessed route module as well as its
2824
+ // individual chunks. This is because, since they have different module
2825
+ // IDs, they are treated as completely separate modules even though they
2826
+ // all reference the same underlying file. This plugin addresses this by
2827
+ // ensuring that any explicit imports of a route module resolve to a
2828
+ // module that simply re-exports from its underlying chunks, if present.
2829
+ async transform(code, id, options) {
2830
+ if (viteCommand !== "build") return;
2831
+ if (options?.ssr) {
2832
+ return;
2833
+ }
2834
+ if (!isRoute(ctx.reactRouterConfig, id)) {
2835
+ return;
2836
+ }
2837
+ if (isRouteVirtualModule(id)) {
2838
+ return;
2839
+ }
2840
+ let { hasRouteChunks, chunkedExports } = await detectRouteChunksIfEnabled(cache, ctx, id, code);
2841
+ if (!hasRouteChunks) {
2842
+ return;
2843
+ }
2844
+ let sourceExports = await getRouteModuleExports(
2845
+ viteChildCompiler,
2846
+ ctx,
2847
+ id
2848
+ );
2849
+ let isMainChunkExport = (name) => !chunkedExports.includes(name);
2850
+ let mainChunkReexports = sourceExports.filter(isMainChunkExport).join(", ");
2851
+ let chunkBasePath = `./${path6.basename(id)}`;
2852
+ return [
2853
+ `export { ${mainChunkReexports} } from "${getRouteChunkModuleId(
2854
+ chunkBasePath,
2855
+ "main"
2856
+ )}";`,
2857
+ ...chunkedExports.map(
2858
+ (exportName) => `export { ${exportName} } from "${getRouteChunkModuleId(
2859
+ chunkBasePath,
2860
+ exportName
2861
+ )}";`
2862
+ )
2863
+ ].filter(Boolean).join("\n");
2864
+ }
2865
+ },
2102
2866
  {
2103
2867
  name: "react-router:build-client-route",
2104
- enforce: "pre",
2105
- async transform(_code, id, options) {
2868
+ async transform(code, id, options) {
2106
2869
  if (!id.endsWith(BUILD_CLIENT_ROUTE_QUERY_STRING)) return;
2107
2870
  let routeModuleId = id.replace(BUILD_CLIENT_ROUTE_QUERY_STRING, "");
2108
2871
  let routeFileName = path6.basename(routeModuleId);
@@ -2111,26 +2874,91 @@ var reactRouterVitePlugin = () => {
2111
2874
  ctx,
2112
2875
  routeModuleId
2113
2876
  );
2114
- let reexports = sourceExports.filter(
2115
- (exportName) => options?.ssr && SERVER_ONLY_ROUTE_EXPORTS.includes(exportName) || CLIENT_ROUTE_EXPORTS.includes(exportName)
2116
- ).join(", ");
2877
+ let { chunkedExports = [] } = options?.ssr ? {} : await detectRouteChunksIfEnabled(cache, ctx, id, code);
2878
+ let reexports = sourceExports.filter((exportName) => {
2879
+ let isRouteEntryExport = options?.ssr && SERVER_ONLY_ROUTE_EXPORTS.includes(exportName) || CLIENT_ROUTE_EXPORTS.includes(exportName);
2880
+ let isChunkedExport = chunkedExports.includes(
2881
+ exportName
2882
+ );
2883
+ return isRouteEntryExport && !isChunkedExport;
2884
+ }).join(", ");
2117
2885
  return `export { ${reexports} } from "./${routeFileName}";`;
2118
2886
  }
2119
2887
  },
2888
+ {
2889
+ name: "react-router:split-route-modules",
2890
+ async transform(code, id, options) {
2891
+ if (options?.ssr) return;
2892
+ if (!isRouteChunkModuleId(id)) return;
2893
+ invariant(
2894
+ viteCommand === "build",
2895
+ "Route modules are only split in build mode"
2896
+ );
2897
+ let chunkName = getRouteChunkNameFromModuleId(id);
2898
+ if (!chunkName) {
2899
+ throw new Error(`Invalid route chunk name "${chunkName}" in "${id}"`);
2900
+ }
2901
+ let chunk = await getRouteChunkIfEnabled(
2902
+ cache,
2903
+ ctx,
2904
+ id,
2905
+ chunkName,
2906
+ code
2907
+ );
2908
+ let preventEmptyChunkSnippet = ({ reason }) => `Math.random()<0&&console.log(${JSON.stringify(reason)});`;
2909
+ if (chunk === null) {
2910
+ return preventEmptyChunkSnippet({
2911
+ reason: "Split round modules disabled"
2912
+ });
2913
+ }
2914
+ let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
2915
+ if (enforceSplitRouteModules && chunkName === "main" && chunk) {
2916
+ let exportNames = getExportNames(chunk.code);
2917
+ validateRouteChunks({
2918
+ ctx,
2919
+ id,
2920
+ valid: {
2921
+ clientAction: !exportNames.includes("clientAction"),
2922
+ clientLoader: !exportNames.includes("clientLoader"),
2923
+ HydrateFallback: !exportNames.includes("HydrateFallback")
2924
+ }
2925
+ });
2926
+ }
2927
+ return chunk ?? preventEmptyChunkSnippet({ reason: `No ${chunkName} chunk` });
2928
+ }
2929
+ },
2120
2930
  {
2121
2931
  name: "react-router:virtual-modules",
2122
2932
  enforce: "pre",
2123
2933
  resolveId(id) {
2124
- const vmod2 = Object.values(virtual).find((vmod3) => vmod3.id === id);
2125
- if (vmod2) return vmod2.resolvedId;
2934
+ let [baseId, queryString] = id.split("?");
2935
+ const vmod2 = Object.values(virtual).find((vmod3) => vmod3.id === baseId);
2936
+ if (vmod2)
2937
+ return vmod2.resolvedId + (queryString ? `?${queryString}` : "");
2126
2938
  },
2127
2939
  async load(id) {
2128
- switch (id) {
2940
+ let [baseId, queryString] = id.split("?");
2941
+ switch (baseId) {
2129
2942
  case virtual.serverBuild.resolvedId: {
2130
- return await getServerEntry();
2943
+ let searchParams = new URLSearchParams(queryString);
2944
+ let routeIds = searchParams.get("route-ids")?.split(",") || void 0;
2945
+ return await getServerEntry({ routeIds });
2131
2946
  }
2132
2947
  case virtual.serverManifest.resolvedId: {
2133
- let reactRouterManifest = ctx.isSsrBuild ? await ctx.getReactRouterServerManifest() : await getReactRouterManifestForDev();
2948
+ let searchParams = new URLSearchParams(queryString);
2949
+ let routeIds = searchParams.get("route-ids")?.split(",") || void 0;
2950
+ let reactRouterManifest = viteCommand === "build" ? (await generateReactRouterManifestsForBuild({
2951
+ routeIds
2952
+ })).reactRouterServerManifest : await getReactRouterManifestForDev();
2953
+ if (!ctx.reactRouterConfig.ssr) {
2954
+ invariant(viteConfig);
2955
+ validateSsrFalsePrerenderExports(
2956
+ viteConfig,
2957
+ ctx,
2958
+ reactRouterManifest,
2959
+ viteChildCompiler
2960
+ );
2961
+ }
2134
2962
  return `export default ${(0, import_jsesc.default)(reactRouterManifest, {
2135
2963
  es6: true
2136
2964
  })};`;
@@ -2171,8 +2999,7 @@ var reactRouterVitePlugin = () => {
2171
2999
  let importerShort = vite2.normalizePath(
2172
3000
  path6.relative(ctx.rootDirectory, importer)
2173
3001
  );
2174
- let isRoute = getRoute(ctx.reactRouterConfig, importer);
2175
- if (isRoute) {
3002
+ if (isRoute(ctx.reactRouterConfig, importer)) {
2176
3003
  let serverOnlyExports = SERVER_ONLY_ROUTE_EXPORTS.map(
2177
3004
  (xport) => `\`${xport}\``
2178
3005
  ).join(", ");
@@ -2211,10 +3038,10 @@ var reactRouterVitePlugin = () => {
2211
3038
  let clientFileRE = /\.client(\.[cm]?[jt]sx?)?$/;
2212
3039
  let clientDirRE = /\/\.client\//;
2213
3040
  if (clientFileRE.test(id) || clientDirRE.test(id)) {
2214
- let exports2 = (0, import_es_module_lexer.parse)(code)[1];
3041
+ let exports2 = getExportNames(code);
2215
3042
  return {
2216
3043
  code: exports2.map(
2217
- ({ n: name }) => name === "default" ? "export default undefined;" : `export const ${name} = undefined;`
3044
+ (name) => name === "default" ? "export default undefined;" : `export const ${name} = undefined;`
2218
3045
  ).join("\n"),
2219
3046
  map: null
2220
3047
  };
@@ -2225,19 +3052,30 @@ var reactRouterVitePlugin = () => {
2225
3052
  {
2226
3053
  name: "react-router:route-exports",
2227
3054
  async transform(code, id, options) {
3055
+ if (isRouteChunkModuleId(id)) {
3056
+ id = id.split("?")[0];
3057
+ }
2228
3058
  let route = getRoute(ctx.reactRouterConfig, id);
2229
3059
  if (!route) return;
2230
- 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));
3060
+ if (!options?.ssr && isSpaModeEnabled(ctx.reactRouterConfig)) {
3061
+ let exportNames = getExportNames(code);
3062
+ let serverOnlyExports = exportNames.filter((exp) => {
3063
+ if (route.id === "root" && exp === "loader") {
3064
+ return false;
3065
+ }
3066
+ return SERVER_ONLY_ROUTE_EXPORTS.includes(exp);
3067
+ });
2232
3068
  if (serverOnlyExports.length > 0) {
2233
3069
  let str = serverOnlyExports.map((e) => `\`${e}\``).join(", ");
2234
- let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://remix.run/guides/spa-mode for more information.`;
3070
+ let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://reactrouter.com/how-to/spa for more information.`;
2235
3071
  throw Error(message);
2236
3072
  }
2237
3073
  if (route.id !== "root") {
2238
- let hasHydrateFallback = (0, import_es_module_lexer.parse)(code)[1].map((exp) => exp.n).some((exp) => exp === "HydrateFallback");
3074
+ let hasHydrateFallback = exportNames.some(
3075
+ (exp) => exp === "HydrateFallback"
3076
+ );
2239
3077
  if (hasHydrateFallback) {
2240
- 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.`;
3078
+ let message = `SPA Mode: Invalid \`HydrateFallback\` export found in \`${route.file}\`. \`HydrateFallback\` is only permitted on the root route in SPA Mode. See https://reactrouter.com/how-to/spa for more information.`;
2241
3079
  throw Error(message);
2242
3080
  }
2243
3081
  }
@@ -2313,6 +3151,9 @@ var reactRouterVitePlugin = () => {
2313
3151
  let isJSX = filepath.endsWith("x");
2314
3152
  let useFastRefresh = !ssr && (isJSX || code.includes(devRuntime));
2315
3153
  if (!useFastRefresh) return;
3154
+ if (isRouteVirtualModule(id)) {
3155
+ return { code: addRefreshWrapper(ctx.reactRouterConfig, code, id) };
3156
+ }
2316
3157
  let result = await babel.transformAsync(code, {
2317
3158
  babelrc: false,
2318
3159
  configFile: false,
@@ -2343,6 +3184,7 @@ var reactRouterVitePlugin = () => {
2343
3184
  let serverManifest = (await server.ssrLoadModule(virtual.serverManifest.id)).default;
2344
3185
  let oldRouteMetadata = serverManifest.routes[route.id];
2345
3186
  let newRouteMetadata = await getRouteMetadata(
3187
+ cache,
2346
3188
  ctx,
2347
3189
  viteChildCompiler,
2348
3190
  route,
@@ -2352,9 +3194,12 @@ var reactRouterVitePlugin = () => {
2352
3194
  if (!oldRouteMetadata || [
2353
3195
  "hasLoader",
2354
3196
  "hasClientLoader",
3197
+ "clientLoaderModule",
2355
3198
  "hasAction",
2356
3199
  "hasClientAction",
2357
- "hasErrorBoundary"
3200
+ "clientActionModule",
3201
+ "hasErrorBoundary",
3202
+ "hydrateFallbackModule"
2358
3203
  ].some((key) => oldRouteMetadata[key] !== newRouteMetadata[key])) {
2359
3204
  invalidateVirtualModules(server);
2360
3205
  }
@@ -2472,13 +3317,30 @@ function getRoute(pluginConfig, file) {
2472
3317
  );
2473
3318
  return route;
2474
3319
  }
2475
- async function getRouteMetadata(ctx, viteChildCompiler, route, readRouteFile) {
3320
+ function isRoute(pluginConfig, file) {
3321
+ return Boolean(getRoute(pluginConfig, file));
3322
+ }
3323
+ async function getRouteMetadata(cache, ctx, viteChildCompiler, route, readRouteFile) {
3324
+ let routeFile = route.file;
2476
3325
  let sourceExports = await getRouteModuleExports(
2477
3326
  viteChildCompiler,
2478
3327
  ctx,
2479
3328
  route.file,
2480
3329
  readRouteFile
2481
3330
  );
3331
+ let { hasRouteChunkByExportName } = await detectRouteChunksIfEnabled(
3332
+ cache,
3333
+ ctx,
3334
+ routeFile,
3335
+ { routeFile, readRouteFile, viteChildCompiler }
3336
+ );
3337
+ let moduleUrl = combineURLs(
3338
+ ctx.publicPath,
3339
+ `${resolveFileUrl(
3340
+ ctx,
3341
+ resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
3342
+ )}`
3343
+ );
2482
3344
  let info = {
2483
3345
  id: route.id,
2484
3346
  parentId: route.parentId,
@@ -2492,14 +3354,11 @@ async function getRouteMetadata(ctx, viteChildCompiler, route, readRouteFile) {
2492
3354
  resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
2493
3355
  )
2494
3356
  ),
2495
- module: combineURLs(
2496
- ctx.publicPath,
2497
- `${resolveFileUrl(
2498
- ctx,
2499
- resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
2500
- )}?import`
2501
- ),
3357
+ module: `${moduleUrl}?import`,
2502
3358
  // Ensure the Vite dev server responds with a JS module
3359
+ clientActionModule: hasRouteChunkByExportName.clientAction ? `${getRouteChunkModuleId(moduleUrl, "clientAction")}` : void 0,
3360
+ clientLoaderModule: hasRouteChunkByExportName.clientLoader ? `${getRouteChunkModuleId(moduleUrl, "clientLoader")}` : void 0,
3361
+ hydrateFallbackModule: hasRouteChunkByExportName.HydrateFallback ? `${getRouteChunkModuleId(moduleUrl, "HydrateFallback")}` : void 0,
2503
3362
  hasAction: sourceExports.includes("action"),
2504
3363
  hasClientAction: sourceExports.includes("clientAction"),
2505
3364
  hasLoader: sourceExports.includes("loader"),
@@ -2509,6 +3368,12 @@ async function getRouteMetadata(ctx, viteChildCompiler, route, readRouteFile) {
2509
3368
  };
2510
3369
  return info;
2511
3370
  }
3371
+ function isPrerenderingEnabled(reactRouterConfig) {
3372
+ return reactRouterConfig.prerender != null && reactRouterConfig.prerender !== false;
3373
+ }
3374
+ function isSpaModeEnabled(reactRouterConfig) {
3375
+ return reactRouterConfig.ssr === false && !isPrerenderingEnabled(reactRouterConfig);
3376
+ }
2512
3377
  async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, serverBuildFile) {
2513
3378
  let serverBuildPath = path6.join(serverBuildDirectory, serverBuildFile);
2514
3379
  let build = await import(url.pathToFileURL(serverBuildPath).toString());
@@ -2519,20 +3384,49 @@ async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, ser
2519
3384
  };
2520
3385
  }
2521
3386
  async function handleSpaMode(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildFile, clientBuildDirectory) {
2522
- let { handler } = await getPrerenderBuildAndHandler(
3387
+ let { build, handler } = await getPrerenderBuildAndHandler(
2523
3388
  viteConfig,
2524
3389
  serverBuildDirectory,
2525
3390
  serverBuildFile
2526
3391
  );
2527
- let request = new Request(`http://localhost${reactRouterConfig.basename}`);
3392
+ let request = new Request(`http://localhost${reactRouterConfig.basename}`, {
3393
+ headers: {
3394
+ // Enable SPA mode in the server runtime and only render down to the root
3395
+ "X-React-Router-SPA-Mode": "yes"
3396
+ }
3397
+ });
2528
3398
  let response = await handler(request);
2529
3399
  let html = await response.text();
2530
- validatePrerenderedResponse(response, html, "SPA Mode", "/");
2531
- validatePrerenderedHtml(html, "SPA Mode");
2532
- await fse.writeFile(path6.join(clientBuildDirectory, "index.html"), html);
2533
- viteConfig.logger.info(
2534
- "SPA Mode: index.html has been written to your " + import_picocolors3.default.bold(path6.relative(process.cwd(), clientBuildDirectory)) + " directory"
2535
- );
3400
+ let isPrerenderSpaFallback = build.prerender.includes("/");
3401
+ let filename3 = isPrerenderSpaFallback ? "__spa-fallback.html" : "index.html";
3402
+ if (response.status !== 200) {
3403
+ if (isPrerenderSpaFallback) {
3404
+ throw new Error(
3405
+ `Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
3406
+ ` + html
3407
+ );
3408
+ } else {
3409
+ throw new Error(
3410
+ `SPA Mode: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
3411
+ ` + html
3412
+ );
3413
+ }
3414
+ }
3415
+ if (!html.includes("window.__reactRouterContext =") || !html.includes("window.__reactRouterRouteModules =")) {
3416
+ throw new Error(
3417
+ "SPA Mode: Did you forget to include `<Scripts/>` in your root route? Your pre-rendered HTML cannot hydrate without `<Scripts />`."
3418
+ );
3419
+ }
3420
+ await fse.writeFile(path6.join(clientBuildDirectory, filename3), html);
3421
+ let prettyDir = path6.relative(process.cwd(), clientBuildDirectory);
3422
+ let prettyPath = path6.join(prettyDir, filename3);
3423
+ if (build.prerender.length > 0) {
3424
+ viteConfig.logger.info(
3425
+ `Prerender (html): SPA Fallback -> ${import_picocolors3.default.bold(prettyPath)}`
3426
+ );
3427
+ } else {
3428
+ viteConfig.logger.info(`SPA Mode: Generated ${import_picocolors3.default.bold(prettyPath)}`);
3429
+ }
2536
3430
  }
2537
3431
  async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildPath, clientBuildDirectory) {
2538
3432
  let { build, handler } = await getPrerenderBuildAndHandler(
@@ -2541,53 +3435,62 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
2541
3435
  serverBuildPath
2542
3436
  );
2543
3437
  let routes = createPrerenderRoutes(build.routes);
2544
- let routesToPrerender;
2545
- if (typeof reactRouterConfig.prerender === "boolean") {
2546
- invariant(reactRouterConfig.prerender, "Expected prerender:true");
2547
- routesToPrerender = determineStaticPrerenderRoutes(
2548
- routes,
2549
- viteConfig,
2550
- true
2551
- );
2552
- } else if (typeof reactRouterConfig.prerender === "function") {
2553
- routesToPrerender = await reactRouterConfig.prerender({
2554
- getStaticPaths: () => determineStaticPrerenderRoutes(routes, viteConfig, false)
2555
- });
2556
- } else {
2557
- routesToPrerender = reactRouterConfig.prerender || ["/"];
2558
- }
2559
3438
  let headers = {
2560
3439
  // Header that can be used in the loader to know if you're running at
2561
3440
  // build time or runtime
2562
3441
  "X-React-Router-Prerender": "yes"
2563
3442
  };
2564
- for (let path7 of routesToPrerender) {
3443
+ for (let path7 of build.prerender) {
2565
3444
  let matches = (0, import_react_router2.matchRoutes)(routes, `/${path7}/`.replace(/^\/\/+/, "/"));
2566
- let hasLoaders = matches?.some((m) => m.route.loader);
2567
- let data;
2568
- if (hasLoaders) {
2569
- data = await prerenderData(
2570
- handler,
2571
- path7,
2572
- clientBuildDirectory,
2573
- reactRouterConfig,
2574
- viteConfig,
2575
- { headers }
2576
- );
2577
- }
3445
+ invariant(
3446
+ matches,
3447
+ `Unable to prerender path because it does not match any routes: ${path7}`
3448
+ );
2578
3449
  let leafRoute = matches ? matches[matches.length - 1].route : null;
2579
3450
  let manifestRoute = leafRoute ? build.routes[leafRoute.id]?.module : null;
2580
- let isResourceRoute = manifestRoute && !manifestRoute.default && !manifestRoute.ErrorBoundary && manifestRoute.loader;
3451
+ let isResourceRoute = manifestRoute && !manifestRoute.default && !manifestRoute.ErrorBoundary;
2581
3452
  if (isResourceRoute) {
2582
- await prerenderResourceRoute(
2583
- handler,
2584
- path7,
2585
- clientBuildDirectory,
2586
- reactRouterConfig,
2587
- viteConfig,
2588
- { headers }
2589
- );
3453
+ invariant(leafRoute);
3454
+ invariant(manifestRoute);
3455
+ if (manifestRoute.loader) {
3456
+ await prerenderData(
3457
+ handler,
3458
+ path7,
3459
+ [leafRoute.id],
3460
+ clientBuildDirectory,
3461
+ reactRouterConfig,
3462
+ viteConfig,
3463
+ { headers }
3464
+ );
3465
+ await prerenderResourceRoute(
3466
+ handler,
3467
+ path7,
3468
+ clientBuildDirectory,
3469
+ reactRouterConfig,
3470
+ viteConfig,
3471
+ { headers }
3472
+ );
3473
+ } else {
3474
+ viteConfig.logger.warn(
3475
+ `\u26A0\uFE0F Skipping prerendering for resource route without a loader: ${leafRoute?.id}`
3476
+ );
3477
+ }
2590
3478
  } else {
3479
+ let hasLoaders = matches.some(
3480
+ (m) => build.assets.routes[m.route.id]?.hasLoader
3481
+ );
3482
+ let data;
3483
+ if (!isResourceRoute && hasLoaders) {
3484
+ data = await prerenderData(
3485
+ handler,
3486
+ path7,
3487
+ null,
3488
+ clientBuildDirectory,
3489
+ reactRouterConfig,
3490
+ viteConfig,
3491
+ { headers }
3492
+ );
3493
+ }
2591
3494
  await prerenderRoute(
2592
3495
  handler,
2593
3496
  path7,
@@ -2603,14 +3506,8 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
2603
3506
  );
2604
3507
  }
2605
3508
  }
2606
- await prerenderManifest(
2607
- build,
2608
- clientBuildDirectory,
2609
- reactRouterConfig,
2610
- viteConfig
2611
- );
2612
3509
  }
2613
- function determineStaticPrerenderRoutes(routes, viteConfig, isBooleanUsage = false) {
3510
+ function getStaticPrerenderPaths(routes) {
2614
3511
  let paths = ["/"];
2615
3512
  let paramRoutes = [];
2616
3513
  function recurse(subtree, prefix = "") {
@@ -2630,28 +3527,33 @@ function determineStaticPrerenderRoutes(routes, viteConfig, isBooleanUsage = fal
2630
3527
  }
2631
3528
  }
2632
3529
  recurse(routes);
2633
- if (isBooleanUsage && paramRoutes.length > 0) {
2634
- viteConfig.logger.warn(
2635
- [
2636
- "\u26A0\uFE0F Paths with dynamic/splat params cannot be prerendered when using `prerender: true`.",
2637
- "You may want to use the `prerender()` API to prerender the following paths:",
2638
- ...paramRoutes.map((p) => " - " + p)
2639
- ].join("\n")
2640
- );
2641
- }
2642
- return paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1"));
3530
+ return {
3531
+ paths: paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1")),
3532
+ paramRoutes
3533
+ };
2643
3534
  }
2644
- async function prerenderData(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
3535
+ async function prerenderData(handler, prerenderPath, onlyRoutes, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
2645
3536
  let normalizedPath = `${reactRouterConfig.basename}${prerenderPath === "/" ? "/_root.data" : `${prerenderPath.replace(/\/$/, "")}.data`}`.replace(/\/\/+/g, "/");
2646
- let request = new Request(`http://localhost${normalizedPath}`, requestInit);
3537
+ let url2 = new URL(`http://localhost${normalizedPath}`);
3538
+ if (onlyRoutes?.length) {
3539
+ url2.searchParams.set("_routes", onlyRoutes.join(","));
3540
+ }
3541
+ let request = new Request(url2, requestInit);
2647
3542
  let response = await handler(request);
2648
3543
  let data = await response.text();
2649
- validatePrerenderedResponse(response, data, "Prerender", normalizedPath);
3544
+ if (response.status !== 200) {
3545
+ throw new Error(
3546
+ `Prerender (data): Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${path6}\` path.
3547
+ ${normalizedPath}`
3548
+ );
3549
+ }
2650
3550
  let outdir = path6.relative(process.cwd(), clientBuildDirectory);
2651
3551
  let outfile = path6.join(outdir, ...normalizedPath.split("/"));
2652
3552
  await fse.ensureDir(path6.dirname(outfile));
2653
3553
  await fse.outputFile(outfile, data);
2654
- viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
3554
+ viteConfig.logger.info(
3555
+ `Prerender (data): ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
3556
+ );
2655
3557
  return data;
2656
3558
  }
2657
3559
  async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
@@ -2662,54 +3564,65 @@ async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reac
2662
3564
  let request = new Request(`http://localhost${normalizedPath}`, requestInit);
2663
3565
  let response = await handler(request);
2664
3566
  let html = await response.text();
2665
- validatePrerenderedResponse(response, html, "Prerender", normalizedPath);
2666
- if (!reactRouterConfig.ssr) {
2667
- validatePrerenderedHtml(html, "Prerender");
3567
+ if (response.status !== 200) {
3568
+ throw new Error(
3569
+ `Prerender (html): Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
3570
+ ${html}`
3571
+ );
2668
3572
  }
2669
3573
  let outdir = path6.relative(process.cwd(), clientBuildDirectory);
2670
3574
  let outfile = path6.join(outdir, ...normalizedPath.split("/"), "index.html");
2671
3575
  await fse.ensureDir(path6.dirname(outfile));
2672
3576
  await fse.outputFile(outfile, html);
2673
- viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
3577
+ viteConfig.logger.info(
3578
+ `Prerender (html): ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
3579
+ );
2674
3580
  }
2675
3581
  async function prerenderResourceRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
2676
3582
  let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(/\/\/+/g, "/").replace(/\/$/g, "");
2677
3583
  let request = new Request(`http://localhost${normalizedPath}`, requestInit);
2678
3584
  let response = await handler(request);
2679
3585
  let text = await response.text();
2680
- validatePrerenderedResponse(response, text, "Prerender", normalizedPath);
3586
+ if (response.status !== 200) {
3587
+ throw new Error(
3588
+ `Prerender (resource): Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
3589
+ ${text}`
3590
+ );
3591
+ }
2681
3592
  let outdir = path6.relative(process.cwd(), clientBuildDirectory);
2682
3593
  let outfile = path6.join(outdir, ...normalizedPath.split("/"));
2683
3594
  await fse.ensureDir(path6.dirname(outfile));
2684
3595
  await fse.outputFile(outfile, text);
2685
- viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
2686
- }
2687
- async function prerenderManifest(build, clientBuildDirectory, reactRouterConfig, viteConfig) {
2688
- let normalizedPath = `${reactRouterConfig.basename}/__manifest`.replace(
2689
- /\/\/+/g,
2690
- "/"
3596
+ viteConfig.logger.info(
3597
+ `Prerender (resource): ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
2691
3598
  );
2692
- let outdir = path6.relative(process.cwd(), clientBuildDirectory);
2693
- let outfile = path6.join(outdir, ...normalizedPath.split("/"));
2694
- await fse.ensureDir(path6.dirname(outfile));
2695
- let manifestData = JSON.stringify(build.assets.routes);
2696
- await fse.outputFile(outfile, manifestData);
2697
- viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
2698
- }
2699
- function validatePrerenderedResponse(response, html, prefix, path7) {
2700
- if (response.status !== 200) {
2701
- throw new Error(
2702
- `${prefix}: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${path7}\` path.
2703
- ${html}`
2704
- );
2705
- }
2706
3599
  }
2707
- function validatePrerenderedHtml(html, prefix) {
2708
- if (!html.includes("window.__reactRouterContext =") || !html.includes("window.__reactRouterRouteModules =")) {
2709
- throw new Error(
2710
- `${prefix}: Did you forget to include <Scripts/> in your root route? Your pre-rendered HTML files cannot hydrate without \`<Scripts />\`.`
2711
- );
3600
+ async function getPrerenderPaths(prerender, ssr, routes, logWarning = false) {
3601
+ let prerenderPaths = [];
3602
+ if (prerender != null && prerender !== false) {
3603
+ let prerenderRoutes = createPrerenderRoutes(routes);
3604
+ if (prerender === true) {
3605
+ let { paths, paramRoutes } = getStaticPrerenderPaths(prerenderRoutes);
3606
+ if (logWarning && !ssr && paramRoutes.length > 0) {
3607
+ console.warn(
3608
+ import_picocolors3.default.yellow(
3609
+ [
3610
+ "\u26A0\uFE0F Paths with dynamic/splat params cannot be prerendered when using `prerender: true`. You may want to use the `prerender()` API to prerender the following paths:",
3611
+ ...paramRoutes.map((p) => " - " + p)
3612
+ ].join("\n")
3613
+ )
3614
+ );
3615
+ }
3616
+ prerenderPaths = paths;
3617
+ } else if (typeof prerender === "function") {
3618
+ prerenderPaths = await prerender({
3619
+ getStaticPaths: () => getStaticPrerenderPaths(prerenderRoutes).paths
3620
+ });
3621
+ } else {
3622
+ prerenderPaths = prerender || ["/"];
3623
+ }
2712
3624
  }
3625
+ return prerenderPaths;
2713
3626
  }
2714
3627
  function groupRoutesByParentId2(manifest) {
2715
3628
  let routes = {};
@@ -2727,24 +3640,445 @@ function groupRoutesByParentId2(manifest) {
2727
3640
  function createPrerenderRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId2(manifest)) {
2728
3641
  return (routesByParentId[parentId] || []).map((route) => {
2729
3642
  let commonRoute = {
2730
- // Always include root due to default boundaries
2731
- hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
2732
3643
  id: route.id,
2733
- path: route.path,
2734
- loader: route.module.loader ? () => null : void 0,
2735
- action: void 0,
2736
- handle: route.module.handle
3644
+ path: route.path
2737
3645
  };
2738
- return route.index ? {
2739
- index: true,
2740
- ...commonRoute
2741
- } : {
2742
- caseSensitive: route.caseSensitive,
3646
+ if (route.index) {
3647
+ return {
3648
+ index: true,
3649
+ ...commonRoute
3650
+ };
3651
+ }
3652
+ return {
2743
3653
  children: createPrerenderRoutes(manifest, route.id, routesByParentId),
2744
3654
  ...commonRoute
2745
3655
  };
2746
3656
  });
2747
3657
  }
3658
+ async function validateSsrFalsePrerenderExports(viteConfig, ctx, manifest, viteChildCompiler) {
3659
+ let prerenderPaths = await getPrerenderPaths(
3660
+ ctx.reactRouterConfig.prerender,
3661
+ ctx.reactRouterConfig.ssr,
3662
+ manifest.routes,
3663
+ true
3664
+ );
3665
+ if (prerenderPaths.length === 0) {
3666
+ return;
3667
+ }
3668
+ let prerenderRoutes = createPrerenderRoutes(manifest.routes);
3669
+ let prerenderedRoutes = /* @__PURE__ */ new Set();
3670
+ for (let path7 of prerenderPaths) {
3671
+ let matches = (0, import_react_router2.matchRoutes)(
3672
+ prerenderRoutes,
3673
+ `/${path7}/`.replace(/^\/\/+/, "/")
3674
+ );
3675
+ invariant(
3676
+ matches,
3677
+ `Unable to prerender path because it does not match any routes: ${path7}`
3678
+ );
3679
+ matches.forEach((m) => prerenderedRoutes.add(m.route.id));
3680
+ }
3681
+ let errors = [];
3682
+ let routeExports = await getRouteManifestModuleExports(
3683
+ viteChildCompiler,
3684
+ ctx
3685
+ );
3686
+ for (let [routeId, route] of Object.entries(manifest.routes)) {
3687
+ let invalidApis = [];
3688
+ invariant(route, "Expected a route object in validateSsrFalseExports");
3689
+ let exports2 = routeExports[route.id];
3690
+ if (exports2.includes("headers")) invalidApis.push("headers");
3691
+ if (exports2.includes("action")) invalidApis.push("action");
3692
+ if (invalidApis.length > 0) {
3693
+ errors.push(
3694
+ `Prerender: ${invalidApis.length} invalid route export(s) in \`${route.id}\` when prerendering with \`ssr:false\`: ${invalidApis.join(", ")}. See https://reactrouter.com/how-to/pre-rendering for more information.`
3695
+ );
3696
+ }
3697
+ if (exports2.includes("loader") && !prerenderedRoutes.has(routeId)) {
3698
+ errors.push(
3699
+ `Prerender: 1 invalid route export in \`${route.id}\` when using \`ssr:false\` with \`prerender\` because the route is never prerendered so the loader will never be called. See https://reactrouter.com/how-to/pre-rendering for more information.`
3700
+ );
3701
+ }
3702
+ }
3703
+ if (errors.length > 0) {
3704
+ viteConfig.logger.error(import_picocolors3.default.red(errors.join("\n")));
3705
+ throw new Error(
3706
+ "Invalid route exports found when prerendering with `ssr:false`"
3707
+ );
3708
+ }
3709
+ }
3710
+ function getAddressableRoutes(routes) {
3711
+ let nonAddressableIds = /* @__PURE__ */ new Set();
3712
+ for (let id in routes) {
3713
+ let route = routes[id];
3714
+ if (route.index) {
3715
+ invariant(
3716
+ route.parentId,
3717
+ `Expected index route "${route.id}" to have "parentId" set`
3718
+ );
3719
+ nonAddressableIds.add(route.parentId);
3720
+ }
3721
+ if (typeof route.path !== "string" && !route.index) {
3722
+ nonAddressableIds.add(id);
3723
+ }
3724
+ }
3725
+ return Object.values(routes).filter(
3726
+ (route) => !nonAddressableIds.has(route.id)
3727
+ );
3728
+ }
3729
+ function getRouteBranch(routes, routeId) {
3730
+ let branch = [];
3731
+ let currentRouteId = routeId;
3732
+ while (currentRouteId) {
3733
+ let route = routes[currentRouteId];
3734
+ invariant(route, `Missing route for ${currentRouteId}`);
3735
+ branch.push(route);
3736
+ currentRouteId = route.parentId;
3737
+ }
3738
+ return branch.reverse();
3739
+ }
3740
+ function hasServerBundles(buildManifest) {
3741
+ return Object.keys(buildManifest.serverBundles ?? {}).length > 0;
3742
+ }
3743
+ function getRoutesByServerBundleId(buildManifest) {
3744
+ if (!buildManifest.routeIdToServerBundleId) {
3745
+ return {};
3746
+ }
3747
+ let routesByServerBundleId = {};
3748
+ for (let [routeId, serverBundleId] of Object.entries(
3749
+ buildManifest.routeIdToServerBundleId
3750
+ )) {
3751
+ routesByServerBundleId[serverBundleId] ??= {};
3752
+ let branch = getRouteBranch(buildManifest.routes, routeId);
3753
+ for (let route of branch) {
3754
+ routesByServerBundleId[serverBundleId][route.id] = route;
3755
+ }
3756
+ }
3757
+ return routesByServerBundleId;
3758
+ }
3759
+ var resolveRouteFileCode = async (ctx, input) => {
3760
+ if (typeof input === "string") return input;
3761
+ invariant(input.viteChildCompiler);
3762
+ return await compileRouteFile(
3763
+ input.viteChildCompiler,
3764
+ ctx,
3765
+ input.routeFile,
3766
+ input.readRouteFile
3767
+ );
3768
+ };
3769
+ async function detectRouteChunksIfEnabled(cache, ctx, id, input) {
3770
+ function noRouteChunks() {
3771
+ return {
3772
+ chunkedExports: [],
3773
+ hasRouteChunks: false,
3774
+ hasRouteChunkByExportName: {
3775
+ clientAction: false,
3776
+ clientLoader: false,
3777
+ HydrateFallback: false
3778
+ }
3779
+ };
3780
+ }
3781
+ if (!ctx.reactRouterConfig.future.unstable_splitRouteModules) {
3782
+ return noRouteChunks();
3783
+ }
3784
+ if (normalizeRelativeFilePath(id, ctx.reactRouterConfig) === ctx.reactRouterConfig.routes.root.file) {
3785
+ return noRouteChunks();
3786
+ }
3787
+ let code = await resolveRouteFileCode(ctx, input);
3788
+ if (!routeChunkExportNames.some((exportName) => code.includes(exportName))) {
3789
+ return noRouteChunks();
3790
+ }
3791
+ let cacheKey = normalizeRelativeFilePath(id, ctx.reactRouterConfig) + (typeof input === "string" ? "" : "?read");
3792
+ return detectRouteChunks(code, cache, cacheKey);
3793
+ }
3794
+ async function getRouteChunkIfEnabled(cache, ctx, id, chunkName, input) {
3795
+ if (!ctx.reactRouterConfig.future.unstable_splitRouteModules) {
3796
+ return null;
3797
+ }
3798
+ let code = await resolveRouteFileCode(ctx, input);
3799
+ let cacheKey = normalizeRelativeFilePath(id, ctx.reactRouterConfig) + (typeof input === "string" ? "" : "?read");
3800
+ return getRouteChunkCode(code, chunkName, cache, cacheKey);
3801
+ }
3802
+ function validateRouteChunks({
3803
+ ctx,
3804
+ id,
3805
+ valid
3806
+ }) {
3807
+ let invalidChunks = Object.entries(valid).filter(([_, isValid]) => !isValid).map(([chunkName]) => chunkName);
3808
+ if (invalidChunks.length === 0) {
3809
+ return;
3810
+ }
3811
+ let plural = invalidChunks.length > 1;
3812
+ throw new Error(
3813
+ [
3814
+ `Error splitting route module: ${normalizeRelativeFilePath(
3815
+ id,
3816
+ ctx.reactRouterConfig
3817
+ )}`,
3818
+ invalidChunks.map((name) => `- ${name}`).join("\n"),
3819
+ `${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.`
3820
+ ].join("\n\n")
3821
+ );
3822
+ }
3823
+ async function cleanBuildDirectory(viteConfig, ctx) {
3824
+ let buildDirectory = ctx.reactRouterConfig.buildDirectory;
3825
+ let isWithinRoot = () => {
3826
+ let relativePath = path6.relative(ctx.rootDirectory, buildDirectory);
3827
+ return !relativePath.startsWith("..") && !path6.isAbsolute(relativePath);
3828
+ };
3829
+ if (viteConfig.build.emptyOutDir ?? isWithinRoot()) {
3830
+ await fse.remove(buildDirectory);
3831
+ }
3832
+ }
3833
+ async function cleanViteManifests(environmentsOptions, ctx) {
3834
+ let viteManifestPaths = Object.entries(environmentsOptions).map(
3835
+ ([environmentName, options]) => {
3836
+ let outDir = options.build?.outDir;
3837
+ invariant(outDir, `Expected build.outDir for ${environmentName}`);
3838
+ return path6.join(outDir, ".vite/manifest.json");
3839
+ }
3840
+ );
3841
+ await Promise.all(
3842
+ viteManifestPaths.map(async (viteManifestPath) => {
3843
+ let manifestExists = await fse.pathExists(viteManifestPath);
3844
+ if (!manifestExists) return;
3845
+ if (!ctx.viteManifestEnabled) {
3846
+ await fse.remove(viteManifestPath);
3847
+ }
3848
+ let viteDir = path6.dirname(viteManifestPath);
3849
+ let viteDirFiles = await fse.readdir(viteDir);
3850
+ if (viteDirFiles.length === 0) {
3851
+ await fse.remove(viteDir);
3852
+ }
3853
+ })
3854
+ );
3855
+ }
3856
+ async function getBuildManifest(ctx) {
3857
+ let { routes, serverBundles, appDirectory } = ctx.reactRouterConfig;
3858
+ if (!serverBundles) {
3859
+ return { routes };
3860
+ }
3861
+ let { normalizePath } = await import("vite");
3862
+ let serverBuildDirectory = getServerBuildDirectory(ctx);
3863
+ let resolvedAppDirectory = path6.resolve(ctx.rootDirectory, appDirectory);
3864
+ let rootRelativeRoutes = Object.fromEntries(
3865
+ Object.entries(routes).map(([id, route]) => {
3866
+ let filePath = path6.join(resolvedAppDirectory, route.file);
3867
+ let rootRelativeFilePath = normalizePath(
3868
+ path6.relative(ctx.rootDirectory, filePath)
3869
+ );
3870
+ return [id, { ...route, file: rootRelativeFilePath }];
3871
+ })
3872
+ );
3873
+ let buildManifest = {
3874
+ serverBundles: {},
3875
+ routeIdToServerBundleId: {},
3876
+ routes: rootRelativeRoutes
3877
+ };
3878
+ await Promise.all(
3879
+ getAddressableRoutes(routes).map(async (route) => {
3880
+ let branch = getRouteBranch(routes, route.id);
3881
+ let serverBundleId = await serverBundles({
3882
+ branch: branch.map(
3883
+ (route2) => configRouteToBranchRoute({
3884
+ ...route2,
3885
+ // Ensure absolute paths are passed to the serverBundles function
3886
+ file: path6.join(resolvedAppDirectory, route2.file)
3887
+ })
3888
+ )
3889
+ });
3890
+ if (typeof serverBundleId !== "string") {
3891
+ throw new Error(`The "serverBundles" function must return a string`);
3892
+ }
3893
+ if (!/^[a-zA-Z0-9-_]+$/.test(serverBundleId)) {
3894
+ throw new Error(
3895
+ `The "serverBundles" function must only return strings containing alphanumeric characters, hyphens and underscores.`
3896
+ );
3897
+ }
3898
+ buildManifest.routeIdToServerBundleId[route.id] = serverBundleId;
3899
+ buildManifest.serverBundles[serverBundleId] ??= {
3900
+ id: serverBundleId,
3901
+ file: normalizePath(
3902
+ path6.join(
3903
+ path6.relative(
3904
+ ctx.rootDirectory,
3905
+ path6.join(serverBuildDirectory, serverBundleId)
3906
+ ),
3907
+ ctx.reactRouterConfig.serverBuildFile
3908
+ )
3909
+ )
3910
+ };
3911
+ })
3912
+ );
3913
+ return buildManifest;
3914
+ }
3915
+ function mergeEnvironmentOptions(base, ...overrides) {
3916
+ let vite2 = getVite();
3917
+ return overrides.reduce(
3918
+ (merged, override) => vite2.mergeConfig(merged, override, false),
3919
+ base
3920
+ );
3921
+ }
3922
+ async function getEnvironmentOptionsResolvers(ctx, buildManifest, viteCommand) {
3923
+ let { serverBuildFile, serverModuleFormat } = ctx.reactRouterConfig;
3924
+ let packageRoot = path6.dirname(
3925
+ require.resolve("@react-router/dev/package.json")
3926
+ );
3927
+ let { moduleSyncEnabled } = await import(`file:///${path6.join(packageRoot, "module-sync-enabled/index.mjs")}`);
3928
+ let vite2 = getVite();
3929
+ let viteServerConditions = [
3930
+ ...vite2.defaultServerConditions ?? [],
3931
+ ...moduleSyncEnabled ? ["module-sync"] : []
3932
+ ];
3933
+ function getBaseOptions({
3934
+ viteUserConfig
3935
+ }) {
3936
+ return {
3937
+ build: {
3938
+ cssMinify: viteUserConfig.build?.cssMinify ?? true,
3939
+ manifest: true,
3940
+ // The manifest is enabled for all builds to detect SSR-only assets
3941
+ rollupOptions: {
3942
+ preserveEntrySignatures: "exports-only",
3943
+ // Silence Rollup "use client" warnings
3944
+ // Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
3945
+ onwarn(warning, defaultHandler) {
3946
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
3947
+ return;
3948
+ }
3949
+ let userHandler = viteUserConfig.build?.rollupOptions?.onwarn;
3950
+ if (userHandler) {
3951
+ userHandler(warning, defaultHandler);
3952
+ } else {
3953
+ defaultHandler(warning);
3954
+ }
3955
+ }
3956
+ }
3957
+ }
3958
+ };
3959
+ }
3960
+ function getBaseServerOptions({
3961
+ viteUserConfig
3962
+ }) {
3963
+ let conditions = viteCommand === "build" ? viteServerConditions : ["development", ...viteServerConditions];
3964
+ return mergeEnvironmentOptions(getBaseOptions({ viteUserConfig }), {
3965
+ resolve: {
3966
+ external: ssrExternals,
3967
+ conditions,
3968
+ externalConditions: conditions
3969
+ },
3970
+ build: {
3971
+ // We move SSR-only assets to client assets. Note that the
3972
+ // SSR build can also emit code-split JS files (e.g. by
3973
+ // dynamic import) under the same assets directory
3974
+ // regardless of "ssrEmitAssets" option, so we also need to
3975
+ // keep these JS files have to be kept as-is.
3976
+ ssrEmitAssets: true,
3977
+ copyPublicDir: false,
3978
+ // Assets in the public directory are only used by the client
3979
+ rollupOptions: {
3980
+ output: {
3981
+ entryFileNames: serverBuildFile,
3982
+ format: serverModuleFormat
3983
+ }
3984
+ }
3985
+ }
3986
+ });
3987
+ }
3988
+ let environmentOptionsResolvers = {
3989
+ client: ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseOptions({ viteUserConfig }), {
3990
+ build: {
3991
+ rollupOptions: {
3992
+ input: [
3993
+ ctx.entryClientFilePath,
3994
+ ...Object.values(ctx.reactRouterConfig.routes).flatMap(
3995
+ (route) => {
3996
+ let routeFilePath = path6.resolve(
3997
+ ctx.reactRouterConfig.appDirectory,
3998
+ route.file
3999
+ );
4000
+ let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
4001
+ let code = fse.readFileSync(routeFilePath, "utf-8");
4002
+ return [
4003
+ `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
4004
+ ...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
4005
+ (exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
4006
+ ) : []
4007
+ ].filter(isNonNullable);
4008
+ }
4009
+ )
4010
+ ],
4011
+ output: {
4012
+ entryFileNames({ moduleIds }) {
4013
+ let routeChunkModuleId = moduleIds.find(isRouteChunkModuleId);
4014
+ let routeChunkName = routeChunkModuleId ? getRouteChunkNameFromModuleId(routeChunkModuleId) : null;
4015
+ let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
4016
+ return `assets/[name]${routeChunkSuffix}-[hash].js`;
4017
+ }
4018
+ }
4019
+ },
4020
+ outDir: getClientBuildDirectory(ctx.reactRouterConfig)
4021
+ }
4022
+ })
4023
+ };
4024
+ if (hasServerBundles(buildManifest)) {
4025
+ for (let [serverBundleId, routes] of Object.entries(
4026
+ getRoutesByServerBundleId(buildManifest)
4027
+ )) {
4028
+ const serverBundleEnvironmentId = serverBundleId.replaceAll("-", "_");
4029
+ const environmentName = `${SSR_BUNDLE_PREFIX}${serverBundleEnvironmentId}`;
4030
+ environmentOptionsResolvers[environmentName] = ({ viteUserConfig }) => mergeEnvironmentOptions(
4031
+ getBaseServerOptions({ viteUserConfig }),
4032
+ {
4033
+ build: {
4034
+ outDir: getServerBuildDirectory(ctx, { serverBundleId }),
4035
+ rollupOptions: {
4036
+ input: `${virtual.serverBuild.id}?route-ids=${Object.keys(
4037
+ routes
4038
+ ).join(",")}`
4039
+ }
4040
+ }
4041
+ },
4042
+ // Ensure server bundle environments extend the user's SSR
4043
+ // environment config if it exists
4044
+ viteUserConfig.environments?.ssr ?? {}
4045
+ );
4046
+ }
4047
+ } else {
4048
+ environmentOptionsResolvers.ssr = ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseServerOptions({ viteUserConfig }), {
4049
+ build: {
4050
+ outDir: getServerBuildDirectory(ctx),
4051
+ rollupOptions: {
4052
+ input: (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig.environments?.ssr?.build?.rollupOptions?.input : viteUserConfig.build?.rollupOptions?.input) ?? virtual.serverBuild.id
4053
+ }
4054
+ }
4055
+ });
4056
+ }
4057
+ return environmentOptionsResolvers;
4058
+ }
4059
+ function resolveEnvironmentsOptions(environmentResolvers, resolverOptions) {
4060
+ let environmentOptions = {};
4061
+ for (let [environmentName, resolver] of Object.entries(
4062
+ environmentResolvers
4063
+ )) {
4064
+ environmentOptions[environmentName] = resolver(resolverOptions);
4065
+ }
4066
+ return environmentOptions;
4067
+ }
4068
+ async function getEnvironmentsOptions(ctx, buildManifest, viteCommand, resolverOptions) {
4069
+ let environmentOptionsResolvers = await getEnvironmentOptionsResolvers(
4070
+ ctx,
4071
+ buildManifest,
4072
+ viteCommand
4073
+ );
4074
+ return resolveEnvironmentsOptions(
4075
+ environmentOptionsResolvers,
4076
+ resolverOptions
4077
+ );
4078
+ }
4079
+ function isNonNullable(x) {
4080
+ return x != null;
4081
+ }
2748
4082
  // Annotate the CommonJS export names for ESM import in node:
2749
4083
  0 && (module.exports = {
2750
4084
  reactRouter