@react-router/dev 0.0.0-experimental-28357fd2a → 0.0.0-experimental-2eb7164

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/CHANGELOG.md CHANGED
@@ -1,32 +1,14 @@
1
1
  # `@react-router/dev`
2
2
 
3
- ## 7.8.0-pre.2
4
-
5
- ### Patch Changes
6
-
7
- - Updated dependencies:
8
- - `react-router@7.8.0-pre.2`
9
- - `@react-router/node@7.8.0-pre.2`
10
- - `@react-router/serve@7.8.0-pre.2`
11
-
12
- ## 7.8.0-pre.1
13
-
14
- ### Patch Changes
15
-
16
- - Updated dependencies:
17
- - `react-router@7.8.0-pre.1`
18
- - `@react-router/node@7.8.0-pre.1`
19
- - `@react-router/serve@7.8.0-pre.1`
20
-
21
- ## 7.8.0-pre.0
3
+ ## 7.8.0
22
4
 
23
5
  ### Patch Changes
24
6
 
25
7
  - Fix rename without mkdir in Vite plugin ([#14105](https://github.com/remix-run/react-router/pull/14105))
26
8
  - Updated dependencies:
27
- - `react-router@7.8.0-pre.0`
28
- - `@react-router/node@7.8.0-pre.0`
29
- - `@react-router/serve@7.8.0-pre.0`
9
+ - `react-router@7.8.0`
10
+ - `@react-router/node@7.8.0`
11
+ - `@react-router/serve@7.8.0`
30
12
 
31
13
  ## 7.7.1
32
14
 
package/dist/cli/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * @react-router/dev v0.0.0-experimental-28357fd2a
3
+ * @react-router/dev v0.0.0-experimental-2eb7164
4
4
  *
5
5
  * Copyright (c) Remix Software Inc.
6
6
  *
@@ -1,3 +1,5 @@
1
+ import "virtual:react-router/unstable_rsc/inject-hmr-runtime";
2
+
1
3
  import { startTransition, StrictMode } from "react";
2
4
  import { hydrateRoot } from "react-dom/client";
3
5
  import {
package/dist/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-28357fd2a
2
+ * @react-router/dev v0.0.0-experimental-2eb7164
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/internal.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-28357fd2a
2
+ * @react-router/dev v0.0.0-experimental-2eb7164
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -46,8 +46,8 @@ module.exports = __toCommonJS(internal_exports);
46
46
 
47
47
  // vite/rsc/plugin.ts
48
48
  var import_plugin_rsc = __toESM(require("@vitejs/plugin-rsc"));
49
- var import_plugin_react = __toESM(require("@vitejs/plugin-react"));
50
49
  var import_es_module_lexer2 = require("es-module-lexer");
50
+ var babel = __toESM(require("@babel/core"));
51
51
 
52
52
  // vite/virtual-module.ts
53
53
  function create(name) {
@@ -247,7 +247,7 @@ function validateRouteConfig({
247
247
  `Route config in "${routeConfigFile}" is invalid.`,
248
248
  root ? `${root}` : [],
249
249
  nested ? Object.entries(nested).map(
250
- ([path4, message]) => `Path: routes.${path4}
250
+ ([path5, message]) => `Path: routes.${path5}
251
251
  ${message}`
252
252
  ) : []
253
253
  ].flat().join("\n\n")
@@ -581,11 +581,11 @@ async function createConfigLoader({
581
581
  if (!fsWatcher) {
582
582
  fsWatcher = import_chokidar.default.watch([root, appDirectory], {
583
583
  ignoreInitial: true,
584
- ignored: (path4) => {
585
- let dirname4 = import_pathe3.default.dirname(path4);
584
+ ignored: (path5) => {
585
+ let dirname4 = import_pathe3.default.dirname(path5);
586
586
  return !dirname4.startsWith(appDirectory) && // Ensure we're only watching files outside of the app directory
587
587
  // that are at the root level, not nested in subdirectories
588
- path4 !== root && // Watch the root directory itself
588
+ path5 !== root && // Watch the root directory itself
589
589
  dirname4 !== root;
590
590
  }
591
591
  });
@@ -785,7 +785,7 @@ function fullpath(lineage2) {
785
785
  if (lineage2.length === 1 && route?.id === "root") return "/";
786
786
  const isLayout = route && route.index !== true && route.path === void 0;
787
787
  if (isLayout) return void 0;
788
- return "/" + lineage2.map((route2) => route2.path?.replace(/^\//, "")?.replace(/\/$/, "")).filter((path4) => path4 !== void 0 && path4 !== "").join("/");
788
+ return "/" + lineage2.map((route2) => route2.path?.replace(/^\//, "")?.replace(/\/$/, "")).filter((path5) => path5 !== void 0 && path5 !== "").join("/");
789
789
  }
790
790
 
791
791
  // typegen/generate.ts
@@ -941,8 +941,8 @@ function routeFilesType({
941
941
  );
942
942
  }
943
943
  function isInAppDirectory(ctx, routeFile) {
944
- const path4 = Path3.resolve(ctx.config.appDirectory, routeFile);
945
- return path4.startsWith(ctx.config.appDirectory);
944
+ const path5 = Path3.resolve(ctx.config.appDirectory, routeFile);
945
+ return path5.startsWith(ctx.config.appDirectory);
946
946
  }
947
947
  function getRouteAnnotations({
948
948
  ctx,
@@ -1054,21 +1054,21 @@ function getRouteAnnotations({
1054
1054
  return { filename: filename2, content };
1055
1055
  }
1056
1056
  function relativeImportSource(from, to) {
1057
- let path4 = Path3.relative(Path3.dirname(from), to);
1058
- let extension = Path3.extname(path4);
1059
- path4 = Path3.join(Path3.dirname(path4), Pathe.filename(path4));
1060
- if (!path4.startsWith("../")) path4 = "./" + path4;
1057
+ let path5 = Path3.relative(Path3.dirname(from), to);
1058
+ let extension = Path3.extname(path5);
1059
+ path5 = Path3.join(Path3.dirname(path5), Pathe.filename(path5));
1060
+ if (!path5.startsWith("../")) path5 = "./" + path5;
1061
1061
  if (!extension || /\.(js|ts)x?$/.test(extension)) {
1062
1062
  extension = ".js";
1063
1063
  }
1064
- return path4 + extension;
1064
+ return path5 + extension;
1065
1065
  }
1066
1066
  function rootDirsPath(ctx, typesPath) {
1067
1067
  const rel = Path3.relative(typesDirectory(ctx), typesPath);
1068
1068
  return Path3.join(ctx.rootDirectory, rel);
1069
1069
  }
1070
- function paramsType(path4) {
1071
- const params = parse2(path4);
1070
+ function paramsType(path5) {
1071
+ const params = parse2(path5);
1072
1072
  return t2.tsTypeLiteral(
1073
1073
  Object.entries(params).map(([param, isRequired]) => {
1074
1074
  const property = t2.tsPropertySignature(
@@ -1158,14 +1158,16 @@ async function watch(rootDirectory, { mode, logger }) {
1158
1158
 
1159
1159
  // vite/rsc/plugin.ts
1160
1160
  var import_fs = require("fs");
1161
- var import_path = require("path");
1161
+ var import_promises2 = require("fs/promises");
1162
+ var import_pathe5 = __toESM(require("pathe"));
1162
1163
 
1163
1164
  // vite/rsc/virtual-route-config.ts
1164
- var import_node_path = __toESM(require("path"));
1165
- function createVirtualRouteConfigCode({
1165
+ var import_pathe4 = __toESM(require("pathe"));
1166
+ function createVirtualRouteConfig({
1166
1167
  appDirectory,
1167
1168
  routeConfig
1168
1169
  }) {
1170
+ let routeIdByFile = /* @__PURE__ */ new Map();
1169
1171
  let code = "export default [";
1170
1172
  const closeRouteSymbol = Symbol("CLOSE_ROUTE");
1171
1173
  let stack = [
@@ -1179,12 +1181,13 @@ function createVirtualRouteConfigCode({
1179
1181
  continue;
1180
1182
  }
1181
1183
  code += "{";
1184
+ const routeFile = import_pathe4.default.resolve(appDirectory, route.file);
1185
+ const routeId = route.id || createRouteId2(route.file, appDirectory);
1186
+ routeIdByFile.set(routeFile, routeId);
1182
1187
  code += `lazy: () => import(${JSON.stringify(
1183
- `${import_node_path.default.resolve(appDirectory, route.file)}?route-module${route.id === "root" ? "&root-route=true" : ""}`
1188
+ `${routeFile}?route-module${routeId === "root" ? "&root-route=true" : ""}`
1184
1189
  )}),`;
1185
- code += `id: ${JSON.stringify(
1186
- route.id || createRouteId2(route.file, appDirectory)
1187
- )},`;
1190
+ code += `id: ${JSON.stringify(routeId)},`;
1188
1191
  if (typeof route.path === "string") {
1189
1192
  code += `path: ${JSON.stringify(route.path)},`;
1190
1193
  }
@@ -1203,10 +1206,10 @@ function createVirtualRouteConfigCode({
1203
1206
  }
1204
1207
  }
1205
1208
  code += "];\n";
1206
- return code;
1209
+ return { code, routeIdByFile };
1207
1210
  }
1208
1211
  function createRouteId2(file, appDirectory) {
1209
- return import_node_path.default.relative(appDirectory, file).replace(/\\+/, "/").slice(0, -import_node_path.default.extname(file).length);
1212
+ return import_pathe4.default.relative(appDirectory, file).replace(/\\+/, "/").slice(0, -import_pathe4.default.extname(file).length);
1210
1213
  }
1211
1214
 
1212
1215
  // vite/rsc/virtual-route-modules.ts
@@ -1220,10 +1223,10 @@ var removeExports = (ast, exportsToRemove) => {
1220
1223
  let markedForRemoval = /* @__PURE__ */ new Set();
1221
1224
  let removedExportLocalNames = /* @__PURE__ */ new Set();
1222
1225
  traverse(ast, {
1223
- ExportDeclaration(path4) {
1224
- if (path4.node.type === "ExportNamedDeclaration") {
1225
- if (path4.node.specifiers.length) {
1226
- path4.node.specifiers = path4.node.specifiers.filter((specifier) => {
1226
+ ExportDeclaration(path5) {
1227
+ if (path5.node.type === "ExportNamedDeclaration") {
1228
+ if (path5.node.specifiers.length) {
1229
+ path5.node.specifiers = path5.node.specifiers.filter((specifier) => {
1227
1230
  if (specifier.type === "ExportSpecifier" && specifier.exported.type === "Identifier") {
1228
1231
  if (exportsToRemove.includes(specifier.exported.name)) {
1229
1232
  exportsFiltered = true;
@@ -1235,12 +1238,12 @@ var removeExports = (ast, exportsToRemove) => {
1235
1238
  }
1236
1239
  return true;
1237
1240
  });
1238
- if (path4.node.specifiers.length === 0) {
1239
- markedForRemoval.add(path4);
1241
+ if (path5.node.specifiers.length === 0) {
1242
+ markedForRemoval.add(path5);
1240
1243
  }
1241
1244
  }
1242
- if (path4.node.declaration?.type === "VariableDeclaration") {
1243
- let declaration = path4.node.declaration;
1245
+ if (path5.node.declaration?.type === "VariableDeclaration") {
1246
+ let declaration = path5.node.declaration;
1244
1247
  declaration.declarations = declaration.declarations.filter(
1245
1248
  (declaration2) => {
1246
1249
  if (declaration2.id.type === "Identifier" && exportsToRemove.includes(declaration2.id.name)) {
@@ -1254,30 +1257,30 @@ var removeExports = (ast, exportsToRemove) => {
1254
1257
  }
1255
1258
  );
1256
1259
  if (declaration.declarations.length === 0) {
1257
- markedForRemoval.add(path4);
1260
+ markedForRemoval.add(path5);
1258
1261
  }
1259
1262
  }
1260
- if (path4.node.declaration?.type === "FunctionDeclaration") {
1261
- let id = path4.node.declaration.id;
1263
+ if (path5.node.declaration?.type === "FunctionDeclaration") {
1264
+ let id = path5.node.declaration.id;
1262
1265
  if (id && exportsToRemove.includes(id.name)) {
1263
- markedForRemoval.add(path4);
1266
+ markedForRemoval.add(path5);
1264
1267
  }
1265
1268
  }
1266
- if (path4.node.declaration?.type === "ClassDeclaration") {
1267
- let id = path4.node.declaration.id;
1269
+ if (path5.node.declaration?.type === "ClassDeclaration") {
1270
+ let id = path5.node.declaration.id;
1268
1271
  if (id && exportsToRemove.includes(id.name)) {
1269
- markedForRemoval.add(path4);
1272
+ markedForRemoval.add(path5);
1270
1273
  }
1271
1274
  }
1272
1275
  }
1273
- if (path4.node.type === "ExportDefaultDeclaration") {
1276
+ if (path5.node.type === "ExportDefaultDeclaration") {
1274
1277
  if (exportsToRemove.includes("default")) {
1275
- markedForRemoval.add(path4);
1276
- if (path4.node.declaration) {
1277
- if (path4.node.declaration.type === "Identifier") {
1278
- removedExportLocalNames.add(path4.node.declaration.name);
1279
- } else if ((path4.node.declaration.type === "FunctionDeclaration" || path4.node.declaration.type === "ClassDeclaration") && path4.node.declaration.id) {
1280
- removedExportLocalNames.add(path4.node.declaration.id.name);
1278
+ markedForRemoval.add(path5);
1279
+ if (path5.node.declaration) {
1280
+ if (path5.node.declaration.type === "Identifier") {
1281
+ removedExportLocalNames.add(path5.node.declaration.name);
1282
+ } else if ((path5.node.declaration.type === "FunctionDeclaration" || path5.node.declaration.type === "ClassDeclaration") && path5.node.declaration.id) {
1283
+ removedExportLocalNames.add(path5.node.declaration.id.name);
1281
1284
  }
1282
1285
  }
1283
1286
  }
@@ -1285,21 +1288,21 @@ var removeExports = (ast, exportsToRemove) => {
1285
1288
  }
1286
1289
  });
1287
1290
  traverse(ast, {
1288
- ExpressionStatement(path4) {
1289
- if (!path4.parentPath.isProgram()) {
1291
+ ExpressionStatement(path5) {
1292
+ if (!path5.parentPath.isProgram()) {
1290
1293
  return;
1291
1294
  }
1292
- if (path4.node.expression.type === "AssignmentExpression") {
1293
- const left = path4.node.expression.left;
1295
+ if (path5.node.expression.type === "AssignmentExpression") {
1296
+ const left = path5.node.expression.left;
1294
1297
  if (left.type === "MemberExpression" && left.object.type === "Identifier" && (exportsToRemove.includes(left.object.name) || removedExportLocalNames.has(left.object.name))) {
1295
- markedForRemoval.add(path4);
1298
+ markedForRemoval.add(path5);
1296
1299
  }
1297
1300
  }
1298
1301
  }
1299
1302
  });
1300
1303
  if (markedForRemoval.size > 0 || exportsFiltered) {
1301
- for (let path4 of markedForRemoval) {
1302
- path4.remove();
1304
+ for (let path5 of markedForRemoval) {
1305
+ path5.remove();
1303
1306
  }
1304
1307
  (0, import_babel_dead_code_elimination.deadCodeElimination)(ast, previouslyReferencedIdentifiers);
1305
1308
  }
@@ -1381,26 +1384,28 @@ function isClientRouteExport(name) {
1381
1384
  }
1382
1385
  function transformVirtualRouteModules({
1383
1386
  id,
1384
- code
1387
+ code,
1388
+ viteCommand
1385
1389
  }) {
1386
1390
  if (!id.includes("route-module")) {
1387
1391
  return;
1388
1392
  }
1389
1393
  if (isVirtualRouteModuleId(id)) {
1390
- return createVirtualRouteModuleCode({ id, code });
1394
+ return createVirtualRouteModuleCode({ id, code, viteCommand });
1391
1395
  }
1392
1396
  if (isVirtualServerRouteModuleId(id)) {
1393
1397
  return createVirtualServerRouteModuleCode({ id, code });
1394
1398
  }
1395
1399
  if (isVirtualClientRouteModuleId(id)) {
1396
- return createVirtualClientRouteModuleCode({ id, code });
1400
+ return createVirtualClientRouteModuleCode({ id, code, viteCommand });
1397
1401
  }
1398
1402
  }
1399
1403
  async function createVirtualRouteModuleCode({
1400
1404
  id,
1401
- code: routeSource
1405
+ code: routeSource,
1406
+ viteCommand
1402
1407
  }) {
1403
- const { staticExports, isServerFirstRoute } = parseRouteExports(routeSource);
1408
+ const { staticExports, isServerFirstRoute, hasClientExports } = parseRouteExports(routeSource);
1404
1409
  const clientModuleId = getVirtualClientModuleId(id);
1405
1410
  const serverModuleId = getVirtualServerModuleId(id);
1406
1411
  let code = "";
@@ -1417,6 +1422,10 @@ async function createVirtualRouteModuleCode({
1417
1422
  `;
1418
1423
  }
1419
1424
  }
1425
+ if (viteCommand === "serve" && !hasClientExports) {
1426
+ code += `export { __ensureClientRouteModuleForHMR } from "${clientModuleId}";
1427
+ `;
1428
+ }
1420
1429
  } else {
1421
1430
  for (const staticExport of staticExports) {
1422
1431
  if (isClientRouteExport(staticExport)) {
@@ -1461,9 +1470,10 @@ function createVirtualServerRouteModuleCode({
1461
1470
  }
1462
1471
  function createVirtualClientRouteModuleCode({
1463
1472
  id,
1464
- code: routeSource
1473
+ code: routeSource,
1474
+ viteCommand
1465
1475
  }) {
1466
- const { staticExports, isServerFirstRoute } = parseRouteExports(routeSource);
1476
+ const { staticExports, isServerFirstRoute, hasClientExports } = parseRouteExports(routeSource);
1467
1477
  const exportsToRemove = isServerFirstRoute ? [...SERVER_ONLY_ROUTE_EXPORTS, ...COMPONENT_EXPORTS] : SERVER_ONLY_ROUTE_EXPORTS;
1468
1478
  const clientRouteModuleAst = import_parser.parse(routeSource, {
1469
1479
  sourceType: "module"
@@ -1484,16 +1494,24 @@ import { createElement as __rr_createElement } from "react";
1484
1494
  `;
1485
1495
  generatorResult.code += `}
1486
1496
  `;
1497
+ }
1498
+ if (viteCommand === "serve" && isServerFirstRoute && !hasClientExports) {
1499
+ generatorResult.code += `
1500
+ export const __ensureClientRouteModuleForHMR = true;`;
1487
1501
  }
1488
1502
  return generatorResult;
1489
1503
  }
1490
1504
  function parseRouteExports(code) {
1491
1505
  const [, exportSpecifiers] = (0, import_es_module_lexer.parse)(code);
1492
1506
  const staticExports = exportSpecifiers.map(({ n: name }) => name);
1507
+ const isServerFirstRoute = staticExports.some(
1508
+ (staticExport) => staticExport === "ServerComponent"
1509
+ );
1493
1510
  return {
1494
1511
  staticExports,
1495
- isServerFirstRoute: staticExports.some(
1496
- (staticExport) => staticExport === "ServerComponent"
1512
+ isServerFirstRoute,
1513
+ hasClientExports: staticExports.some(
1514
+ isServerFirstRoute ? isClientNonComponentExport : isClientRouteExport
1497
1515
  )
1498
1516
  };
1499
1517
  }
@@ -1521,11 +1539,14 @@ function reactRouterRSCVitePlugin() {
1521
1539
  let configLoader;
1522
1540
  let config;
1523
1541
  let typegenWatcherPromise;
1542
+ let viteCommand;
1543
+ let routeIdByFile;
1524
1544
  return [
1525
1545
  {
1526
1546
  name: "react-router/rsc/config",
1527
1547
  async config(viteUserConfig, { command, mode }) {
1528
1548
  await import_es_module_lexer2.init;
1549
+ viteCommand = command;
1529
1550
  const rootDirectory = getRootDirectory(viteUserConfig);
1530
1551
  const watch2 = command === "serve";
1531
1552
  configLoader = await createConfigLoader({ rootDirectory, mode, watch: watch2 });
@@ -1533,10 +1554,62 @@ function reactRouterRSCVitePlugin() {
1533
1554
  if (!configResult.ok) throw new Error(configResult.error);
1534
1555
  config = configResult.value;
1535
1556
  return {
1557
+ resolve: {
1558
+ dedupe: [
1559
+ // https://react.dev/warnings/invalid-hook-call-warning#duplicate-react
1560
+ "react",
1561
+ "react-dom",
1562
+ // Avoid router duplicates since mismatching routers cause `Error:
1563
+ // You must render this element inside a <Remix> element`.
1564
+ "react-router",
1565
+ "react-router/dom",
1566
+ "react-router-dom"
1567
+ ]
1568
+ },
1569
+ optimizeDeps: {
1570
+ esbuildOptions: {
1571
+ jsx: "automatic"
1572
+ },
1573
+ include: [
1574
+ // Pre-bundle React dependencies to avoid React duplicates,
1575
+ // even if React dependencies are not direct dependencies.
1576
+ // https://react.dev/warnings/invalid-hook-call-warning#duplicate-react
1577
+ "react",
1578
+ "react/jsx-runtime",
1579
+ "react/jsx-dev-runtime",
1580
+ "react-dom",
1581
+ "react-dom/client"
1582
+ ]
1583
+ },
1584
+ esbuild: {
1585
+ jsx: "automatic",
1586
+ jsxDev: viteCommand !== "build"
1587
+ },
1536
1588
  environments: {
1537
1589
  client: { build: { outDir: "build/client" } },
1538
1590
  rsc: { build: { outDir: "build/server" } },
1539
1591
  ssr: { build: { outDir: "build/server/__ssr_build" } }
1592
+ },
1593
+ build: {
1594
+ rollupOptions: {
1595
+ // Copied from https://github.com/vitejs/vite-plugin-react/blob/c602225271d4acf462ba00f8d6d8a2e42492c5cd/packages/common/warning.ts
1596
+ onwarn(warning, defaultHandler) {
1597
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" && (warning.message.includes("use client") || warning.message.includes("use server"))) {
1598
+ return;
1599
+ }
1600
+ if (warning.code === "SOURCEMAP_ERROR" && warning.message.includes("resolve original location") && warning.pos === 0) {
1601
+ return;
1602
+ }
1603
+ if (viteUserConfig.build?.rollupOptions?.onwarn) {
1604
+ viteUserConfig.build.rollupOptions.onwarn(
1605
+ warning,
1606
+ defaultHandler
1607
+ );
1608
+ } else {
1609
+ defaultHandler(warning);
1610
+ }
1611
+ }
1612
+ }
1540
1613
  }
1541
1614
  };
1542
1615
  },
@@ -1575,56 +1648,238 @@ function reactRouterRSCVitePlugin() {
1575
1648
  },
1576
1649
  load(id) {
1577
1650
  if (id === virtual.routeConfig.resolvedId) {
1578
- return createVirtualRouteConfigCode({
1651
+ const result = createVirtualRouteConfig({
1579
1652
  appDirectory: config.appDirectory,
1580
1653
  routeConfig: config.unstable_routeConfig
1581
1654
  });
1655
+ routeIdByFile = result.routeIdByFile;
1656
+ return result.code;
1582
1657
  }
1583
1658
  }
1584
1659
  },
1585
1660
  {
1586
1661
  name: "react-router/rsc/virtual-route-modules",
1587
1662
  transform(code, id) {
1588
- return transformVirtualRouteModules({ code, id });
1663
+ return transformVirtualRouteModules({ code, id, viteCommand });
1664
+ }
1665
+ },
1666
+ {
1667
+ name: "react-router/rsc/hmr/inject-runtime",
1668
+ enforce: "pre",
1669
+ resolveId(id) {
1670
+ if (id === virtual.injectHmrRuntime.id) {
1671
+ return virtual.injectHmrRuntime.resolvedId;
1672
+ }
1673
+ },
1674
+ async load(id) {
1675
+ if (id !== virtual.injectHmrRuntime.resolvedId) return;
1676
+ return viteCommand === "serve" ? [
1677
+ `import RefreshRuntime from "${virtual.hmrRuntime.id}"`,
1678
+ "RefreshRuntime.injectIntoGlobalHook(window)",
1679
+ "window.$RefreshReg$ = () => {}",
1680
+ "window.$RefreshSig$ = () => (type) => type",
1681
+ "window.__vite_plugin_react_preamble_installed__ = true"
1682
+ ].join("\n") : "";
1683
+ }
1684
+ },
1685
+ {
1686
+ name: "react-router/rsc/hmr/runtime",
1687
+ enforce: "pre",
1688
+ resolveId(id) {
1689
+ if (id === virtual.hmrRuntime.id) return virtual.hmrRuntime.resolvedId;
1690
+ },
1691
+ async load(id) {
1692
+ if (id !== virtual.hmrRuntime.resolvedId) return;
1693
+ const reactRefreshDir = import_pathe5.default.dirname(
1694
+ require.resolve("react-refresh/package.json")
1695
+ );
1696
+ const reactRefreshRuntimePath = import_pathe5.default.join(
1697
+ reactRefreshDir,
1698
+ "cjs/react-refresh-runtime.development.js"
1699
+ );
1700
+ return [
1701
+ "const exports = {}",
1702
+ await (0, import_promises2.readFile)(reactRefreshRuntimePath, "utf8"),
1703
+ await (0, import_promises2.readFile)(
1704
+ require.resolve("./static/rsc-refresh-utils.mjs"),
1705
+ "utf8"
1706
+ ),
1707
+ "export default exports"
1708
+ ].join("\n");
1709
+ }
1710
+ },
1711
+ {
1712
+ name: "react-router/rsc/hmr/react-refresh",
1713
+ async transform(code, id, options) {
1714
+ if (viteCommand !== "serve") return;
1715
+ if (id.includes("/node_modules/")) return;
1716
+ const filepath = id.split("?")[0];
1717
+ const extensionsRE = /\.(jsx?|tsx?|mdx?)$/;
1718
+ if (!extensionsRE.test(filepath)) return;
1719
+ const devRuntime = "react/jsx-dev-runtime";
1720
+ const ssr = options?.ssr === true;
1721
+ const isJSX = filepath.endsWith("x");
1722
+ const useFastRefresh = !ssr && (isJSX || code.includes(devRuntime));
1723
+ if (!useFastRefresh) return;
1724
+ const routeId = routeIdByFile?.get(filepath);
1725
+ if (routeId !== void 0) {
1726
+ return { code: addRefreshWrapper({ routeId, code, id }) };
1727
+ }
1728
+ const result = await babel.transformAsync(code, {
1729
+ babelrc: false,
1730
+ configFile: false,
1731
+ filename: id,
1732
+ sourceFileName: filepath,
1733
+ parserOpts: {
1734
+ sourceType: "module",
1735
+ allowAwaitOutsideFunction: true
1736
+ },
1737
+ plugins: [[require("react-refresh/babel"), { skipEnvCheck: true }]],
1738
+ sourceMaps: true
1739
+ });
1740
+ if (result === null) return;
1741
+ code = result.code;
1742
+ const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;
1743
+ if (refreshContentRE.test(code)) {
1744
+ code = addRefreshWrapper({ code, id });
1745
+ }
1746
+ return { code, map: result.map };
1747
+ }
1748
+ },
1749
+ {
1750
+ name: "react-router/rsc/hmr/updates",
1751
+ async hotUpdate({ server, file, modules }) {
1752
+ if (this.environment.name !== "rsc") return;
1753
+ const isServerOnlyChange = (server.environments.client.moduleGraph.getModulesByFile(file)?.size ?? 0) === 0;
1754
+ for (const mod of getModulesWithImporters(modules)) {
1755
+ if (!mod.file) continue;
1756
+ const normalizedPath = import_pathe5.default.normalize(mod.file);
1757
+ const routeId = routeIdByFile?.get(normalizedPath);
1758
+ if (routeId !== void 0) {
1759
+ const routeSource = await (0, import_promises2.readFile)(normalizedPath, "utf8");
1760
+ const virtualRouteModuleCode = (await server.environments.rsc.pluginContainer.transform(
1761
+ routeSource,
1762
+ `${normalizedPath}?route-module`
1763
+ )).code;
1764
+ const { staticExports } = parseRouteExports(virtualRouteModuleCode);
1765
+ const hasAction = staticExports.includes("action");
1766
+ const hasComponent = staticExports.includes("default");
1767
+ const hasErrorBoundary = staticExports.includes("ErrorBoundary");
1768
+ const hasLoader = staticExports.includes("loader");
1769
+ server.hot.send({
1770
+ type: "custom",
1771
+ event: "react-router:hmr",
1772
+ data: {
1773
+ routeId,
1774
+ isServerOnlyChange,
1775
+ hasAction,
1776
+ hasComponent,
1777
+ hasErrorBoundary,
1778
+ hasLoader
1779
+ }
1780
+ });
1781
+ }
1782
+ }
1783
+ return modules;
1589
1784
  }
1590
1785
  },
1591
- (0, import_plugin_react.default)(),
1592
1786
  (0, import_plugin_rsc.default)({ entries: getRscEntries() })
1593
1787
  ];
1594
1788
  }
1595
1789
  var virtual = {
1596
- routeConfig: create("unstable_rsc/routes")
1790
+ routeConfig: create("unstable_rsc/routes"),
1791
+ injectHmrRuntime: create("unstable_rsc/inject-hmr-runtime"),
1792
+ hmrRuntime: create("unstable_rsc/runtime")
1597
1793
  };
1598
1794
  function getRootDirectory(viteUserConfig) {
1599
1795
  return viteUserConfig.root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd();
1600
1796
  }
1601
1797
  function getRscEntries() {
1602
- const entriesDir = (0, import_path.join)(
1798
+ const entriesDir = (0, import_pathe5.join)(
1603
1799
  getDevPackageRoot(),
1604
1800
  "dist",
1605
1801
  "config",
1606
1802
  "default-rsc-entries"
1607
1803
  );
1608
1804
  return {
1609
- client: (0, import_path.join)(entriesDir, "entry.client.tsx"),
1610
- rsc: (0, import_path.join)(entriesDir, "entry.rsc.tsx"),
1611
- ssr: (0, import_path.join)(entriesDir, "entry.ssr.tsx")
1805
+ client: (0, import_pathe5.join)(entriesDir, "entry.client.tsx"),
1806
+ rsc: (0, import_pathe5.join)(entriesDir, "entry.rsc.tsx"),
1807
+ ssr: (0, import_pathe5.join)(entriesDir, "entry.ssr.tsx")
1612
1808
  };
1613
1809
  }
1614
1810
  function getDevPackageRoot() {
1615
- const currentDir = (0, import_path.dirname)(__dirname);
1811
+ const currentDir = (0, import_pathe5.dirname)(__dirname);
1616
1812
  let dir = currentDir;
1617
- while (dir !== (0, import_path.dirname)(dir)) {
1813
+ while (dir !== (0, import_pathe5.dirname)(dir)) {
1618
1814
  try {
1619
- const packageJsonPath = (0, import_path.join)(dir, "package.json");
1815
+ const packageJsonPath = (0, import_pathe5.join)(dir, "package.json");
1620
1816
  (0, import_fs.readFileSync)(packageJsonPath, "utf-8");
1621
1817
  return dir;
1622
1818
  } catch {
1623
- dir = (0, import_path.dirname)(dir);
1819
+ dir = (0, import_pathe5.dirname)(dir);
1624
1820
  }
1625
1821
  }
1626
1822
  throw new Error("Could not find package.json");
1627
1823
  }
1824
+ function getModulesWithImporters(modules) {
1825
+ const visited = /* @__PURE__ */ new Set();
1826
+ const result = /* @__PURE__ */ new Set();
1827
+ function walk(module2) {
1828
+ if (visited.has(module2)) return;
1829
+ visited.add(module2);
1830
+ result.add(module2);
1831
+ for (const importer of module2.importers) {
1832
+ walk(importer);
1833
+ }
1834
+ }
1835
+ for (const module2 of modules) {
1836
+ walk(module2);
1837
+ }
1838
+ return result;
1839
+ }
1840
+ function addRefreshWrapper({
1841
+ routeId,
1842
+ code,
1843
+ id
1844
+ }) {
1845
+ const acceptExports = routeId !== void 0 ? CLIENT_NON_COMPONENT_EXPORTS : [];
1846
+ return REACT_REFRESH_HEADER.replaceAll("__SOURCE__", JSON.stringify(id)) + code + REACT_REFRESH_FOOTER.replaceAll("__SOURCE__", JSON.stringify(id)).replaceAll("__ACCEPT_EXPORTS__", JSON.stringify(acceptExports)).replaceAll("__ROUTE_ID__", JSON.stringify(routeId));
1847
+ }
1848
+ var REACT_REFRESH_HEADER = `
1849
+ import RefreshRuntime from "${virtual.hmrRuntime.id}";
1850
+
1851
+ const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
1852
+ let prevRefreshReg;
1853
+ let prevRefreshSig;
1854
+
1855
+ if (import.meta.hot && !inWebWorker) {
1856
+ if (!window.__vite_plugin_react_preamble_installed__) {
1857
+ throw new Error(
1858
+ "React Router Vite plugin can't detect preamble. Something is wrong."
1859
+ );
1860
+ }
1861
+
1862
+ prevRefreshReg = window.$RefreshReg$;
1863
+ prevRefreshSig = window.$RefreshSig$;
1864
+ window.$RefreshReg$ = (type, id) => {
1865
+ RefreshRuntime.register(type, __SOURCE__ + " " + id)
1866
+ };
1867
+ window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
1868
+ }`.replaceAll("\n", "");
1869
+ var REACT_REFRESH_FOOTER = `
1870
+ if (import.meta.hot && !inWebWorker) {
1871
+ window.$RefreshReg$ = prevRefreshReg;
1872
+ window.$RefreshSig$ = prevRefreshSig;
1873
+ RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
1874
+ RefreshRuntime.registerExportsForReactRefresh(__SOURCE__, currentExports);
1875
+ import.meta.hot.accept((nextExports) => {
1876
+ if (!nextExports) return;
1877
+ __ROUTE_ID__ && window.__reactRouterRouteModuleUpdates.set(__ROUTE_ID__, nextExports);
1878
+ const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(currentExports, nextExports, __ACCEPT_EXPORTS__);
1879
+ if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);
1880
+ });
1881
+ });
1882
+ }`;
1628
1883
 
1629
1884
  // internal.ts
1630
1885
  var __INTERNAL_DO_NOT_USE_OR_YOU_WILL_GET_A_STRONGLY_WORDED_LETTER__ = {
package/dist/routes.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-28357fd2a
2
+ * @react-router/dev v0.0.0-experimental-2eb7164
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -0,0 +1,126 @@
1
+ // adapted from https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/src/refreshUtils.js
2
+ // This file gets injected into the browser as a part of the HMR runtime
3
+
4
+ function debounce(fn, delay) {
5
+ let handle;
6
+ return () => {
7
+ clearTimeout(handle);
8
+ handle = setTimeout(fn, delay);
9
+ };
10
+ }
11
+
12
+ /* eslint-disable no-undef */
13
+ const enqueueUpdate = debounce(async () => {
14
+ if (routeUpdates.size > 0) {
15
+ const routeUpdateByRouteId = new Map();
16
+ for (const routeUpdate of routeUpdates) {
17
+ const routeId = routeUpdate.routeId;
18
+ const routeModule = window.__reactRouterRouteModuleUpdates.get(routeId);
19
+ if (routeModule) {
20
+ routeUpdateByRouteId.set(routeId, { routeModule, ...routeUpdate });
21
+ }
22
+ }
23
+ routeUpdates.clear();
24
+ __reactRouterDataRouter._updateRoutesForHMR(routeUpdateByRouteId);
25
+ }
26
+
27
+ try {
28
+ window.__reactRouterHdrActive = true;
29
+ await __reactRouterDataRouter.revalidate();
30
+ } finally {
31
+ window.__reactRouterHdrActive = false;
32
+ }
33
+
34
+ exports.performReactRefresh();
35
+ }, 16);
36
+
37
+ // Taken from https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/lib/runtime/RefreshUtils.js#L141
38
+ // This allows to resister components not detected by SWC like styled component
39
+ function registerExportsForReactRefresh(filename, moduleExports) {
40
+ for (const key in moduleExports) {
41
+ if (key === "__esModule") continue;
42
+ const exportValue = moduleExports[key];
43
+ if (exports.isLikelyComponentType(exportValue)) {
44
+ // 'export' is required to avoid key collision when renamed exports that
45
+ // shadow a local component name: https://github.com/vitejs/vite-plugin-react/issues/116
46
+ // The register function has an identity check to not register twice the same component,
47
+ // so this is safe to not used the same key here.
48
+ exports.register(exportValue, filename + " export " + key);
49
+ }
50
+ }
51
+ }
52
+
53
+ function validateRefreshBoundaryAndEnqueueUpdate(
54
+ prevExports,
55
+ nextExports,
56
+ // non-component exports that are handled by the framework (e.g. `meta` and `links` for route modules)
57
+ acceptExports = [],
58
+ ) {
59
+ if (
60
+ !predicateOnExport(
61
+ prevExports,
62
+ (key) => key in nextExports || acceptExports.includes(key),
63
+ )
64
+ ) {
65
+ return "Could not Fast Refresh (export removed)";
66
+ }
67
+ if (
68
+ !predicateOnExport(
69
+ nextExports,
70
+ (key) => key in prevExports || acceptExports.includes(key),
71
+ )
72
+ ) {
73
+ return "Could not Fast Refresh (new export)";
74
+ }
75
+
76
+ let hasExports = false;
77
+ const allExportsAreHandledOrUnchanged = predicateOnExport(
78
+ nextExports,
79
+ (key, value) => {
80
+ hasExports = true;
81
+ // React Router can handle additional exports (e.g. `meta` and `links`)
82
+ if (acceptExports.includes(key)) return true;
83
+ // React Fast Refresh can handle component exports
84
+ if (exports.isLikelyComponentType(value)) return true;
85
+ // Unchanged exports are implicitly handled
86
+ return prevExports[key] === nextExports[key];
87
+ },
88
+ );
89
+ if (hasExports && allExportsAreHandledOrUnchanged) {
90
+ enqueueUpdate();
91
+ } else {
92
+ return "Could not Fast Refresh. Learn more at https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#consistent-components-exports";
93
+ }
94
+ }
95
+
96
+ function predicateOnExport(moduleExports, predicate) {
97
+ for (const key in moduleExports) {
98
+ if (key === "__esModule") continue;
99
+ const desc = Object.getOwnPropertyDescriptor(moduleExports, key);
100
+ if (desc && desc.get) return false;
101
+ if (!predicate(key, moduleExports[key])) return false;
102
+ }
103
+ return true;
104
+ }
105
+
106
+ // Hides vite-ignored dynamic import so that Vite can skip analysis if no other
107
+ // dynamic import is present (https://github.com/vitejs/vite/pull/12732)
108
+ function __hmr_import(module) {
109
+ return import(/* @vite-ignore */ module);
110
+ }
111
+
112
+ const routeUpdates = new Set();
113
+ window.__reactRouterRouteModuleUpdates = new Map();
114
+
115
+ import.meta.hot.on("react-router:hmr", async (routeUpdate) => {
116
+ routeUpdates.add(routeUpdate);
117
+ if (routeUpdate.isServerOnlyChange) {
118
+ enqueueUpdate();
119
+ }
120
+ });
121
+
122
+ exports.__hmr_import = __hmr_import;
123
+ exports.registerExportsForReactRefresh = registerExportsForReactRefresh;
124
+ exports.validateRefreshBoundaryAndEnqueueUpdate =
125
+ validateRefreshBoundaryAndEnqueueUpdate;
126
+ exports.enqueueUpdate = enqueueUpdate;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-28357fd2a
2
+ * @react-router/dev v0.0.0-experimental-2eb7164
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/vite.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-28357fd2a
2
+ * @react-router/dev v0.0.0-experimental-2eb7164
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-router/dev",
3
- "version": "0.0.0-experimental-28357fd2a",
3
+ "version": "0.0.0-experimental-2eb7164",
4
4
  "description": "Dev tools and CLI for React Router",
5
5
  "homepage": "https://reactrouter.com",
6
6
  "bugs": {
@@ -73,7 +73,6 @@
73
73
  "@babel/traverse": "^7.27.7",
74
74
  "@babel/types": "^7.27.7",
75
75
  "@npmcli/package-json": "^4.0.1",
76
- "@vitejs/plugin-react": "^4.5.2",
77
76
  "@vitejs/plugin-rsc": "0.4.11",
78
77
  "arg": "^5.0.1",
79
78
  "babel-dead-code-elimination": "^1.0.6",
@@ -92,7 +91,7 @@
92
91
  "tinyglobby": "^0.2.14",
93
92
  "valibot": "^0.41.0",
94
93
  "vite-node": "^3.2.2",
95
- "@react-router/node": "0.0.0-experimental-28357fd2a"
94
+ "@react-router/node": "0.0.0-experimental-2eb7164"
96
95
  },
97
96
  "devDependencies": {
98
97
  "@types/babel__core": "^7.20.5",
@@ -115,15 +114,15 @@
115
114
  "vite": "^6.1.0",
116
115
  "wireit": "0.14.9",
117
116
  "wrangler": "^4.23.0",
118
- "@react-router/serve": "0.0.0-experimental-28357fd2a",
119
- "react-router": "^0.0.0-experimental-28357fd2a"
117
+ "react-router": "^0.0.0-experimental-2eb7164",
118
+ "@react-router/serve": "0.0.0-experimental-2eb7164"
120
119
  },
121
120
  "peerDependencies": {
122
121
  "typescript": "^5.1.0",
123
122
  "vite": "^5.1.0 || ^6.0.0 || ^7.0.0",
124
123
  "wrangler": "^3.28.2 || ^4.0.0",
125
- "@react-router/serve": "^0.0.0-experimental-28357fd2a",
126
- "react-router": "^0.0.0-experimental-28357fd2a"
124
+ "@react-router/serve": "^0.0.0-experimental-2eb7164",
125
+ "react-router": "^0.0.0-experimental-2eb7164"
127
126
  },
128
127
  "peerDependenciesMeta": {
129
128
  "@react-router/serve": {