@react-router/dev 7.14.0 → 7.14.2

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,5 +1,36 @@
1
1
  # `@react-router/dev`
2
2
 
3
+ ## v7.14.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix typegen for layouts without pages ([[aabf4a1](https://github.com/remix-run/react-router/commit/aabf4a1))
8
+
9
+ Previously, typegen could produce `pages: ;` in `.react-router/types/+routes.ts` when a route corresponded to 0 pages.
10
+ Now, `pages: never;` is correctly generated for those cases.
11
+
12
+ ### Unstable Changes
13
+
14
+ ⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
15
+
16
+ - For `unstable_reactRouterRSC` Vite plugin consumers, require `@vitejs/plugin-react` in user Vite config, and more reliably split route modules. ([#14965](https://github.com/remix-run/react-router/pull/14965)) ([[aabf4a1](https://github.com/remix-run/react-router/commit/aabf4a1))
17
+
18
+ - ⚠️ This is a breaking change if you have begun using the `unstable_reactRouterRSC` Vite plugin - please install `@vitejs/plugin-react` and add the `react` plugin to your Vite plugins array.
19
+ - Updated dependencies:
20
+ - [`react-router@7.14.2`](https://github.com/remix-run/react-router/releases/tag/react-router@7.14.2)
21
+ - [`@react-router/node@7.14.2`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@7.14.2)
22
+ - [`@react-router/serve@7.14.2`](https://github.com/remix-run/react-router/releases/tag/@react-router/serve@7.14.2)
23
+
24
+ ## v7.14.1
25
+
26
+ ### Patch Changes
27
+
28
+ - Add TypeScript 6 support to peer dependency ranges
29
+ - Updated dependencies:
30
+ - [`react-router@7.14.1`](https://github.com/remix-run/react-router/releases/tag/react-router@7.14.1)
31
+ - [`@react-router/node@7.14.1`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@7.14.1)
32
+ - [`@react-router/serve@7.14.1`](https://github.com/remix-run/react-router/releases/tag/@react-router/serve@7.14.1)
33
+
3
34
  ## 7.14.0
4
35
 
5
36
  ### Minor Changes
@@ -8,7 +39,7 @@
8
39
 
9
40
  ### Patch Changes
10
41
 
11
- - support for prerendering multiple server bundles with v8\_viteEnvironmentApi ([#14921](https://github.com/remix-run/react-router/pull/14921))
42
+ - support for prerendering multiple server bundles with v8_viteEnvironmentApi ([#14921](https://github.com/remix-run/react-router/pull/14921))
12
43
 
13
44
  - rsc framework mode prerender / spa mode support ([#14907](https://github.com/remix-run/react-router/pull/14907))
14
45
 
@@ -89,7 +120,6 @@
89
120
  By default, React Router normalizes the `request.url` passed to your `loader`, `action`, and `middleware` functions by removing React Router's internal implementation details (`.data` suffixes, `index` + `_routes` query params).
90
121
 
91
122
  Enabling this flag removes that normalization and passes the raw HTTP `request` instance to your handlers. This provides a few benefits:
92
-
93
123
  - Reduces server-side overhead by eliminating multiple `new Request()` calls on the critical path
94
124
  - Allows you to distinguish document from data requests in your handlers base don the presence of a `.data` suffix (useful for observability purposes)
95
125
 
@@ -165,25 +195,25 @@
165
195
 
166
196
  | URL `/a/b/c` | **HTTP pathname** | **`request` pathname\`** |
167
197
  | ------------ | ----------------- | ------------------------ |
168
- | **Document** | `/a/b/c` | `/a/b/c` ✅ |
169
- | **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
198
+ | **Document** | `/a/b/c` | `/a/b/c` ✅ |
199
+ | **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
170
200
 
171
201
  | URL `/a/b/c/` | **HTTP pathname** | **`request` pathname\`** |
172
202
  | ------------- | ----------------- | ------------------------ |
173
- | **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
203
+ | **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
174
204
  | **Data** | `/a/b/c.data` | `/a/b/c` ⚠️ |
175
205
 
176
206
  With this flag enabled, these pathnames will be made consistent though a new `_.data` format for client-side `.data` requests:
177
207
 
178
208
  | URL `/a/b/c` | **HTTP pathname** | **`request` pathname\`** |
179
209
  | ------------ | ----------------- | ------------------------ |
180
- | **Document** | `/a/b/c` | `/a/b/c` ✅ |
181
- | **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
210
+ | **Document** | `/a/b/c` | `/a/b/c` ✅ |
211
+ | **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
182
212
 
183
213
  | URL `/a/b/c/` | **HTTP pathname** | **`request` pathname\`** |
184
214
  | ------------- | ------------------ | ------------------------ |
185
- | **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
186
- | **Data** | `/a/b/c/_.data` ⬅️ | `/a/b/c/` ✅ |
215
+ | **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
216
+ | **Data** | `/a/b/c/_.data` ⬅️ | `/a/b/c/` ✅ |
187
217
 
188
218
  This a bug fix but we are putting it behind an opt-in flag because it has the potential to be a "breaking bug fix" if you are relying on the URL format for any other application or caching logic.
189
219
 
@@ -441,7 +471,6 @@
441
471
  - Stabilize middleware and context APIs. ([#14215](https://github.com/remix-run/react-router/pull/14215))
442
472
 
443
473
  We have removed the `unstable_` prefix from the following APIs and they are now considered stable and ready for production use:
444
-
445
474
  - [`RouterContextProvider`](https://reactrouter.com/api/utils/RouterContextProvider)
446
475
  - [`createContext`](https://reactrouter.com/api/utils/createContext)
447
476
  - `createBrowserRouter` [`getContext`](https://reactrouter.com/api/data-routers/createBrowserRouter#optsgetcontext) option
@@ -1184,7 +1213,6 @@
1184
1213
  ```
1185
1214
 
1186
1215
  This initial implementation targets type inference for:
1187
-
1188
1216
  - `Params` : Path parameters from your routing config in `routes.ts` including file-based routing
1189
1217
  - `LoaderData` : Loader data from `loader` and/or `clientLoader` within your route module
1190
1218
  - `ActionData` : Action data from `action` and/or `clientAction` within your route module
@@ -1199,7 +1227,6 @@
1199
1227
  ```
1200
1228
 
1201
1229
  Check out our docs for more:
1202
-
1203
1230
  - [_Explanations > Type Safety_](https://reactrouter.com/dev/guides/explanation/type-safety)
1204
1231
  - [_How-To > Setting up type safety_](https://reactrouter.com/dev/guides/how-to/setting-up-type-safety)
1205
1232
 
@@ -1399,7 +1426,6 @@
1399
1426
  - Vite: Provide `Unstable_ServerBundlesFunction` and `Unstable_VitePluginConfig` types ([#8654](https://github.com/remix-run/remix/pull/8654))
1400
1427
 
1401
1428
  - Vite: add `--sourcemapClient` and `--sourcemapServer` flags to `remix vite:build` ([#8613](https://github.com/remix-run/remix/pull/8613))
1402
-
1403
1429
  - `--sourcemapClient`
1404
1430
 
1405
1431
  - `--sourcemapClient=inline`
@@ -1736,7 +1762,6 @@
1736
1762
  - Add support for `clientLoader`/`clientAction`/`HydrateFallback` route exports ([RFC](https://github.com/remix-run/remix/discussions/7634)) ([#8173](https://github.com/remix-run/remix/pull/8173))
1737
1763
 
1738
1764
  Remix now supports loaders/actions that run on the client (in addition to, or instead of the loader/action that runs on the server). While we still recommend server loaders/actions for the majority of your data needs in a Remix app - these provide some levers you can pull for more advanced use-cases such as:
1739
-
1740
1765
  - Leveraging a data source local to the browser (i.e., `localStorage`)
1741
1766
  - Managing a client-side cache of server data (like `IndexedDB`)
1742
1767
  - Bypassing the Remix server in a BFF setup and hitting your API directly from the browser
@@ -2140,7 +2165,6 @@
2140
2165
  - Output esbuild metafiles for bundle analysis ([#6772](https://github.com/remix-run/remix/pull/6772))
2141
2166
 
2142
2167
  Written to server build directory (`build/` by default):
2143
-
2144
2168
  - `metafile.css.json`
2145
2169
  - `metafile.js.json` (browser JS)
2146
2170
  - `metafile.server.json` (server JS)
@@ -2238,7 +2262,6 @@
2238
2262
  - built-in tls support ([#6483](https://github.com/remix-run/remix/pull/6483))
2239
2263
 
2240
2264
  New options:
2241
-
2242
2265
  - `--tls-key` / `tlsKey`: TLS key
2243
2266
  - `--tls-cert` / `tlsCert`: TLS Certificate
2244
2267
 
@@ -2509,7 +2532,6 @@
2509
2532
  ```
2510
2533
 
2511
2534
  The dev server will:
2512
-
2513
2535
  - force `NODE_ENV=development` and warn you if it was previously set to something else
2514
2536
  - rebuild your app whenever your Remix app code changes
2515
2537
  - restart your app server whenever rebuilds succeed
package/dist/cli/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * @react-router/dev v7.14.0
3
+ * @react-router/dev v7.14.2
4
4
  *
5
5
  * Copyright (c) Remix Software Inc.
6
6
  *
@@ -1078,7 +1078,7 @@ function routeFilesType({
1078
1078
  t2.tsPropertySignature(
1079
1079
  t2.identifier("page"),
1080
1080
  t2.tsTypeAnnotation(
1081
- pages ? t2.tsUnionType(
1081
+ pages.size > 0 ? t2.tsUnionType(
1082
1082
  Array.from(pages).map(
1083
1083
  (page) => t2.tsLiteralType(t2.stringLiteral(page))
1084
1084
  )
package/dist/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v7.14.0
2
+ * @react-router/dev v7.14.2
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/routes.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v7.14.0
2
+ * @react-router/dev v7.14.2
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v7.14.0
2
+ * @react-router/dev v7.14.2
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 v7.14.0
2
+ * @react-router/dev v7.14.2
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1096,7 +1096,7 @@ function routeFilesType({
1096
1096
  t2.tsPropertySignature(
1097
1097
  t2.identifier("page"),
1098
1098
  t2.tsTypeAnnotation(
1099
- pages ? t2.tsUnionType(
1099
+ pages.size > 0 ? t2.tsUnionType(
1100
1100
  Array.from(pages).map(
1101
1101
  (page) => t2.tsLiteralType(t2.stringLiteral(page))
1102
1102
  )
@@ -5677,7 +5677,6 @@ function escapeHtml(html) {
5677
5677
  // vite/rsc/plugin.ts
5678
5678
  var import_es_module_lexer3 = require("es-module-lexer");
5679
5679
  var Path5 = __toESM(require("pathe"));
5680
- var babel2 = __toESM(require("@babel/core"));
5681
5680
  var import_picocolors5 = __toESM(require("picocolors"));
5682
5681
  var import_fs = require("fs");
5683
5682
  var import_promises4 = require("fs/promises");
@@ -5685,12 +5684,91 @@ var import_pathe6 = __toESM(require("pathe"));
5685
5684
 
5686
5685
  // vite/rsc/virtual-route-config.ts
5687
5686
  var import_pathe5 = __toESM(require("pathe"));
5687
+ var js = String.raw;
5688
5688
  function createVirtualRouteConfig({
5689
5689
  appDirectory,
5690
5690
  routeConfig
5691
5691
  }) {
5692
5692
  let routeIdByFile = /* @__PURE__ */ new Map();
5693
- let code = "export default [";
5693
+ let code = js`import * as React from "react";
5694
+ function frameworkRoute(lazy) {
5695
+ return async () => {
5696
+ const mod = await lazy();
5697
+ let Component;
5698
+ let Layout;
5699
+ let ErrorBoundary;
5700
+ let HydrateFallback;
5701
+ if ("default" in mod && mod.default) {
5702
+ if ("ServerComponent" in mod && mod.ServerComponent) {
5703
+ throw new Error("Module cannot have both a default export and a ServerComponent export");
5704
+ }
5705
+ Component = mod.default;
5706
+ } else if ("ServerComponent" in mod && mod.ServerComponent) {
5707
+ Component = mod.ServerComponent;
5708
+ }
5709
+ if ("Layout" in mod && mod.Layout) {
5710
+ if ("ServerLayout" in mod && mod.ServerLayout) {
5711
+ throw new Error("Module cannot have both a Layout export and a ServerLayout export");
5712
+ }
5713
+ Layout = mod.Layout;
5714
+ } else if ("ServerLayout" in mod && mod.ServerLayout) {
5715
+ Layout = mod.ServerLayout;
5716
+ }
5717
+ if ("ErrorBoundary" in mod && mod.ErrorBoundary) {
5718
+ if ("ServerErrorBoundary" in mod && mod.ServerErrorBoundary) {
5719
+ throw new Error(
5720
+ "Module cannot have both an ErrorBoundary export and a ServerErrorBoundary export",
5721
+ );
5722
+ }
5723
+ ErrorBoundary = mod.ErrorBoundary;
5724
+ } else if ("ServerErrorBoundary" in mod && mod.ServerErrorBoundary) {
5725
+ ErrorBoundary = mod.ServerErrorBoundary;
5726
+ }
5727
+ if ("HydrateFallback" in mod && mod.HydrateFallback) {
5728
+ if ("ServerHydrateFallback" in mod && mod.ServerHydrateFallback) {
5729
+ throw new Error(
5730
+ "Module cannot have both a HydrateFallback export and a ServerHydrateFallback export",
5731
+ );
5732
+ }
5733
+ HydrateFallback = mod.HydrateFallback;
5734
+ } else if ("ServerHydrateFallback" in mod && mod.ServerHydrateFallback) {
5735
+ HydrateFallback = mod.ServerHydrateFallback;
5736
+ }
5737
+
5738
+ const {
5739
+ action,
5740
+ clientAction,
5741
+ clientLoader,
5742
+ clientMiddleware,
5743
+ handle,
5744
+ headers,
5745
+ links,
5746
+ loader,
5747
+ meta,
5748
+ middleware,
5749
+ shouldRevalidate,
5750
+ } = mod;
5751
+
5752
+ return {
5753
+ Component,
5754
+ ErrorBoundary,
5755
+ HydrateFallback,
5756
+ Layout,
5757
+ action,
5758
+ clientAction,
5759
+ clientLoader,
5760
+ clientMiddleware,
5761
+ handle,
5762
+ headers,
5763
+ links,
5764
+ loader,
5765
+ meta,
5766
+ middleware,
5767
+ shouldRevalidate,
5768
+ };
5769
+ };
5770
+ }
5771
+ export default [`;
5694
5772
  const closeRouteSymbol = Symbol("CLOSE_ROUTE");
5695
5773
  let stack = [
5696
5774
  ...routeConfig
@@ -5706,9 +5784,9 @@ function createVirtualRouteConfig({
5706
5784
  const routeFile = import_pathe5.default.resolve(appDirectory, route.file);
5707
5785
  const routeId = route.id || createRouteId2(route.file, appDirectory);
5708
5786
  routeIdByFile.set(routeFile, routeId);
5709
- code += `lazy: () => import(${JSON.stringify(
5710
- `${routeFile}?route-module`
5711
- )}),`;
5787
+ code += `lazy: frameworkRoute(() => import(${JSON.stringify(
5788
+ `${routeFile}`
5789
+ )})),`;
5712
5790
  code += `id: ${JSON.stringify(routeId)},`;
5713
5791
  if (typeof route.path === "string") {
5714
5792
  code += `path: ${JSON.stringify(route.path)},`;
@@ -5736,227 +5814,282 @@ function createRouteId2(file, appDirectory) {
5736
5814
 
5737
5815
  // vite/rsc/virtual-route-modules.ts
5738
5816
  var import_es_module_lexer2 = require("es-module-lexer");
5739
- var SERVER_COMPONENT_EXPORTS = [
5740
- "ServerComponent",
5741
- "ServerLayout",
5742
- "ServerHydrateFallback",
5743
- "ServerErrorBoundary"
5744
- ];
5745
- var SERVER_COMPONENT_EXPORTS_SET = new Set(SERVER_COMPONENT_EXPORTS);
5746
- function isServerComponentExport(name) {
5747
- return SERVER_COMPONENT_EXPORTS_SET.has(name);
5748
- }
5749
- var SERVER_ROUTE_EXPORTS = [
5750
- ...SERVER_COMPONENT_EXPORTS,
5751
- "loader",
5752
- "action",
5753
- "middleware",
5754
- "headers"
5755
- ];
5756
- var SERVER_ROUTE_EXPORTS_SET = new Set(SERVER_ROUTE_EXPORTS);
5757
- function isServerRouteExport(name) {
5758
- return SERVER_ROUTE_EXPORTS_SET.has(name);
5759
- }
5760
- var CLIENT_NON_COMPONENT_EXPORTS2 = [
5761
- "clientAction",
5762
- "clientLoader",
5763
- "clientMiddleware",
5764
- "handle",
5765
- "meta",
5766
- "links",
5767
- "shouldRevalidate"
5768
- ];
5769
- var CLIENT_ROUTE_EXPORTS2 = [
5770
- ...CLIENT_NON_COMPONENT_EXPORTS2,
5771
- "default",
5772
- "ErrorBoundary",
5773
- "HydrateFallback",
5774
- "Layout"
5775
- ];
5776
- var CLIENT_ROUTE_EXPORTS_SET = new Set(CLIENT_ROUTE_EXPORTS2);
5777
- function isClientRouteExport(name) {
5778
- return CLIENT_ROUTE_EXPORTS_SET.has(name);
5779
- }
5780
- var mutuallyExclusiveRouteExports = /* @__PURE__ */ new Map([
5781
- ["ErrorBoundary", "ServerErrorBoundary"],
5782
- ["HydrateFallback", "ServerHydrateFallback"],
5783
- ["Layout", "ServerLayout"],
5784
- ["default", "ServerComponent"]
5785
- ]);
5786
- var ROUTE_EXPORTS = [
5787
- ...SERVER_ROUTE_EXPORTS,
5788
- ...CLIENT_ROUTE_EXPORTS2
5789
- ];
5790
- var ROUTE_EXPORTS_SET = new Set(ROUTE_EXPORTS);
5791
- function isRouteExport(name) {
5792
- return ROUTE_EXPORTS_SET.has(name);
5793
- }
5794
- function isCustomRouteExport(name) {
5795
- return !isRouteExport(name);
5796
- }
5797
- function hasReactServerCondition(viteEnvironment) {
5798
- return viteEnvironment.config.resolve.conditions.includes("react-server");
5799
- }
5800
- function transformVirtualRouteModules({
5801
- id,
5802
- code,
5803
- viteCommand,
5804
- routeIdByFile,
5805
- rootRouteFile,
5806
- viteEnvironment
5807
- }) {
5808
- if (isVirtualRouteModuleId(id) || routeIdByFile.has(id)) {
5809
- return createVirtualRouteModuleCode({
5810
- id,
5811
- code,
5812
- rootRouteFile,
5813
- viteCommand,
5814
- viteEnvironment
5815
- });
5816
- }
5817
- if (isVirtualServerRouteModuleId(id)) {
5818
- return createVirtualServerRouteModuleCode({
5819
- id,
5820
- code,
5821
- viteEnvironment
5822
- });
5823
- }
5824
- if (isVirtualClientRouteModuleId(id)) {
5825
- return createVirtualClientRouteModuleCode({
5826
- id,
5827
- code,
5828
- rootRouteFile,
5829
- viteCommand
5830
- });
5831
- }
5832
- }
5833
- async function createVirtualRouteModuleCode({
5834
- id,
5835
- code: routeSource,
5836
- rootRouteFile,
5837
- viteCommand,
5838
- viteEnvironment
5817
+ var ENSURE_CLIENT_ROUTE_MODULE_CHUNK_FOR_HMR = `
5818
+ import * as ___EnsureClientRouteModuleForHMR_REACT___ from "react";
5819
+ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRouteModuleForHMR_REACT___.createElement(___EnsureClientRouteModuleForHMR_REACT___.Fragment, null) }
5820
+ `;
5821
+ function virtualRouteModulesPlugin({
5822
+ enforceSplitRouteModules,
5823
+ environments: { client = ["client", "ssr"], server = ["rsc"] } = {},
5824
+ getRouteIdForFile,
5825
+ isRootRouteModule,
5826
+ transformToJs,
5827
+ shouldTransform
5839
5828
  }) {
5840
- const isReactServer = hasReactServerCondition(viteEnvironment);
5841
- const { staticExports, hasClientExports } = parseRouteExports(routeSource);
5842
- for (const exportName of staticExports) {
5843
- if (mutuallyExclusiveRouteExports.has(exportName)) {
5844
- const conflictingExport = mutuallyExclusiveRouteExports.get(exportName);
5845
- if (staticExports.includes(conflictingExport)) {
5846
- throw new Error(
5847
- `Route module cannot export both "${exportName}" and "${conflictingExport}". Please choose one or the other.`
5848
- );
5829
+ let clientEnvironments = new Set(client);
5830
+ let serverEnvironments = new Set(server);
5831
+ let cache = /* @__PURE__ */ new Map();
5832
+ async function createClientRouteEntry(id, code, isRootRouteModule2, routeId) {
5833
+ let result = "";
5834
+ let routeChunks = detectRouteChunks2(cache, id, code, isRootRouteModule2);
5835
+ let { staticExports } = await parseRouteExports(code);
5836
+ validateRouteModuleExports(staticExports);
5837
+ let needsReactImport = false;
5838
+ for (let exportName of staticExports) {
5839
+ if (isServerRouteExport(exportName)) {
5840
+ continue;
5849
5841
  }
5850
- }
5851
- }
5852
- const clientModuleId = getVirtualClientModuleId(id);
5853
- const serverModuleId = getVirtualServerModuleId(id);
5854
- let code = "";
5855
- if (isReactServer && staticExports.some(isServerComponentExport)) {
5856
- code += `import React from "react";
5842
+ if ((exportName === "clientAction" || exportName === "clientLoader") && routeChunks.hasRouteChunkByExportName[exportName]) {
5843
+ result += `export const ${exportName} = async (...args) => import("${createId(id, "client-route-module", exportName)}").then(mod => mod.${exportName}(...args));
5844
+ `;
5845
+ } else if (exportName === "HydrateFallback") {
5846
+ needsReactImport = true;
5847
+ result += `export const ${exportName} = React.lazy(() => import("${createId(
5848
+ id,
5849
+ "client-route-module",
5850
+ routeChunks.hasRouteChunkByExportName[exportName] ? exportName : "shared"
5851
+ )}").then(mod => ({ default: mod.${exportName} })));
5852
+ `;
5853
+ } else {
5854
+ result += `export { ${exportName} } from "${createId(
5855
+ id,
5856
+ "client-route-module",
5857
+ routeChunks.hasRouteChunkByExportName[exportName] ? exportName : "shared"
5858
+ )}";
5857
5859
  `;
5860
+ }
5861
+ }
5862
+ if (needsReactImport) {
5863
+ result = `import * as React from "react";
5864
+ ${result}`;
5865
+ }
5866
+ if (enforceSplitRouteModules() && !isRootRouteModule2) {
5867
+ let { hasRouteChunkByExportName } = routeChunks;
5868
+ let hasClientAction = staticExports.includes("clientAction");
5869
+ let hasClientLoader = staticExports.includes("clientLoader");
5870
+ let hasClientMiddleware = staticExports.includes("clientMiddleware");
5871
+ let hasHydrateFallback = staticExports.includes("HydrateFallback");
5872
+ validateRouteChunks2({
5873
+ id: routeId,
5874
+ valid: {
5875
+ clientAction: !hasClientAction || hasRouteChunkByExportName.clientAction,
5876
+ clientLoader: !hasClientLoader || hasRouteChunkByExportName.clientLoader,
5877
+ clientMiddleware: !hasClientMiddleware || hasRouteChunkByExportName.clientMiddleware,
5878
+ HydrateFallback: !hasHydrateFallback || hasRouteChunkByExportName.HydrateFallback
5879
+ }
5880
+ });
5881
+ }
5882
+ return {
5883
+ code: '"use client";\n' + result
5884
+ };
5858
5885
  }
5859
- for (const staticExport of staticExports) {
5860
- if (isReactServer && isServerComponentExport(staticExport)) {
5861
- code += `import { ${staticExport} as ${staticExport}WithoutCss } from "${serverModuleId}";
5886
+ async function createServerRouteEntry(id, code, isRootRouteModule2, routeId) {
5887
+ let result = "";
5888
+ let routeChunks = detectRouteChunks2(cache, id, code, isRootRouteModule2);
5889
+ let { staticExports } = await parseRouteExports(code);
5890
+ validateRouteModuleExports(staticExports);
5891
+ let needsReactImport = false;
5892
+ for (let exportName of staticExports) {
5893
+ if (isClientRouteExport(exportName)) {
5894
+ result += `export { ${exportName} } from "${createId(
5895
+ id,
5896
+ "client-route-module",
5897
+ routeChunks.hasRouteChunkByExportName[exportName] ? exportName : "shared"
5898
+ )}";
5862
5899
  `;
5863
- code += `export ${staticExport === "ServerComponent" ? "default " : " "}function ${staticExport.replace(/^Server/, "")}(props) {
5900
+ } else if (isServerComponentExport(exportName)) {
5901
+ needsReactImport = true;
5902
+ result += `import { ${exportName} as ${exportName}WithoutCss } from "${createId(id, "server-route-module")}";
5864
5903
  `;
5865
- code += ` return React.createElement(React.Fragment, null,
5904
+ result += `export function ${exportName}(props) {
5866
5905
  `;
5867
- code += ` import.meta.viteRsc.loadCss(),
5906
+ result += ` return React.createElement(React.Fragment, null,
5868
5907
  `;
5869
- code += ` React.createElement(${staticExport}WithoutCss, props),
5908
+ result += ` import.meta.viteRsc.loadCss(),
5870
5909
  `;
5871
- code += ` );
5910
+ result += ` React.createElement(EnsureClientRouteModuleForHMR___, null),
5872
5911
  `;
5873
- code += `}
5912
+ result += ` React.createElement(${exportName}WithoutCss, props),
5874
5913
  `;
5875
- } else if (isReactServer && isServerRouteExport(staticExport)) {
5876
- code += `export { ${staticExport} } from "${serverModuleId}";
5914
+ result += ` );
5877
5915
  `;
5878
- } else if (isClientRouteExport(staticExport)) {
5879
- code += `export { ${staticExport} } from "${clientModuleId}";
5916
+ result += `}
5880
5917
  `;
5881
- } else if (isCustomRouteExport(staticExport)) {
5882
- code += `export { ${staticExport} } from "${isReactServer ? serverModuleId : clientModuleId}";
5918
+ } else {
5919
+ result += `export { ${exportName} } from "${createId(id, "server-route-module")}";
5883
5920
  `;
5921
+ }
5884
5922
  }
5885
- }
5886
- if (isRootRouteFile({ id, rootRouteFile }) && !staticExports.includes("ErrorBoundary") && !staticExports.includes("ServerErrorBoundary")) {
5887
- code += `export { ErrorBoundary } from "${clientModuleId}";
5888
- `;
5889
- }
5890
- if (viteCommand === "serve" && !hasClientExports) {
5891
- code += `export { __ensureClientRouteModuleForHMR } from "${clientModuleId}";
5923
+ if (needsReactImport) {
5924
+ result = `import * as React from "react";
5925
+ import { EnsureClientRouteModuleForHMR___ } from "${createId(id, "client-route-module", "shared")}";
5926
+
5927
+ ${result}`;
5928
+ }
5929
+ if (isRootRouteModule2 && !staticExports.includes("ErrorBoundary") && !staticExports.includes("ServerErrorBoundary")) {
5930
+ result += `export { ErrorBoundary } from "${createId(id, "client-route-module", "shared")}";
5892
5931
  `;
5932
+ }
5933
+ if (enforceSplitRouteModules() && !isRootRouteModule2) {
5934
+ let { hasRouteChunkByExportName } = routeChunks;
5935
+ let hasClientAction = staticExports.includes("clientAction");
5936
+ let hasClientLoader = staticExports.includes("clientLoader");
5937
+ let hasClientMiddleware = staticExports.includes("clientMiddleware");
5938
+ let hasHydrateFallback = staticExports.includes("HydrateFallback");
5939
+ validateRouteChunks2({
5940
+ id: routeId,
5941
+ valid: {
5942
+ clientAction: !hasClientAction || hasRouteChunkByExportName.clientAction,
5943
+ clientLoader: !hasClientLoader || hasRouteChunkByExportName.clientLoader,
5944
+ clientMiddleware: !hasClientMiddleware || hasRouteChunkByExportName.clientMiddleware,
5945
+ HydrateFallback: !hasHydrateFallback || hasRouteChunkByExportName.HydrateFallback
5946
+ }
5947
+ });
5948
+ }
5949
+ return {
5950
+ code: result
5951
+ };
5893
5952
  }
5894
- return code;
5895
- }
5896
- function createVirtualServerRouteModuleCode({
5897
- id,
5898
- code: routeSource,
5899
- viteEnvironment
5900
- }) {
5901
- if (!hasReactServerCondition(viteEnvironment)) {
5902
- throw new Error(
5903
- [
5904
- "Virtual server route module was loaded outside of the RSC environment.",
5905
- `Environment Name: ${viteEnvironment.name}`,
5906
- `Module ID: ${id}`
5907
- ].join("\n")
5908
- );
5953
+ function createServerRouteModule(code) {
5954
+ const ast = import_parser.parse(code, {
5955
+ sourceType: "module"
5956
+ });
5957
+ removeExports(ast, CLIENT_ROUTE_EXPORTS2);
5958
+ return generate(ast);
5909
5959
  }
5910
- const { staticExports } = parseRouteExports(routeSource);
5911
- const clientModuleId = getVirtualClientModuleId(id);
5912
- const serverRouteModuleAst = import_parser.parse(routeSource, {
5913
- sourceType: "module"
5914
- });
5915
- removeExports(serverRouteModuleAst, CLIENT_ROUTE_EXPORTS2);
5916
- const generatorResult = generate(serverRouteModuleAst);
5917
- for (const staticExport of staticExports) {
5918
- if (isClientRouteExport(staticExport)) {
5919
- generatorResult.code += "\n";
5920
- generatorResult.code += `export { ${staticExport} } from "${clientModuleId}";
5921
- `;
5960
+ async function createClientRouteModuleChunk(id, code, chunk, routeId, isRootRouteModule2, isDevMode) {
5961
+ let routeChunks = detectRouteChunks2(cache, id, code, isRootRouteModule2);
5962
+ const ast = import_parser.parse(code, {
5963
+ sourceType: "module"
5964
+ });
5965
+ const { staticExports } = await parseRouteExports(code);
5966
+ if (chunk === "shared") {
5967
+ removeExports(ast, [
5968
+ ...SERVER_ROUTE_EXPORTS,
5969
+ ...routeChunks.chunkedExports
5970
+ ]);
5971
+ } else {
5972
+ const toRemove = /* @__PURE__ */ new Set([...SERVER_ROUTE_EXPORTS, ...staticExports]);
5973
+ toRemove.delete(chunk);
5974
+ removeExports(ast, Array.from(toRemove));
5922
5975
  }
5923
- }
5924
- return generatorResult;
5925
- }
5926
- function createVirtualClientRouteModuleCode({
5927
- id,
5928
- code: routeSource,
5929
- rootRouteFile,
5930
- viteCommand
5931
- }) {
5932
- const { staticExports, hasClientExports } = parseRouteExports(routeSource);
5933
- const clientRouteModuleAst = import_parser.parse(routeSource, {
5934
- sourceType: "module"
5935
- });
5936
- removeExports(clientRouteModuleAst, SERVER_ROUTE_EXPORTS);
5937
- const generatorResult = generate(clientRouteModuleAst);
5938
- generatorResult.code = '"use client";' + generatorResult.code;
5939
- if (isRootRouteFile({ id, rootRouteFile }) && !staticExports.includes("ErrorBoundary") && !staticExports.includes("ServerErrorBoundary")) {
5940
- const hasRootLayout = staticExports.includes("Layout");
5941
- generatorResult.code += `
5976
+ const generated = generate(ast);
5977
+ let result = '"use client";\n' + generated.code;
5978
+ if (chunk === "shared") {
5979
+ if (isRootRouteModule2 && !staticExports.includes("ErrorBoundary") && !staticExports.includes("ServerErrorBoundary")) {
5980
+ const hasRootLayout = staticExports.includes("Layout") || staticExports.includes("ServerLayout");
5981
+ result += `
5942
5982
  import { createElement as __rr_createElement } from "react";
5943
5983
  `;
5944
- generatorResult.code += `import { UNSAFE_RSCDefaultRootErrorBoundary } from "react-router";
5984
+ result += `import { UNSAFE_RSCDefaultRootErrorBoundary } from "react-router";
5945
5985
  `;
5946
- generatorResult.code += `export function ErrorBoundary() {
5986
+ result += `export function ErrorBoundary() {
5947
5987
  `;
5948
- generatorResult.code += ` return __rr_createElement(UNSAFE_RSCDefaultRootErrorBoundary, { hasRootLayout: ${hasRootLayout} });
5988
+ result += ` return __rr_createElement(UNSAFE_RSCDefaultRootErrorBoundary, { hasRootLayout: ${hasRootLayout} });
5949
5989
  `;
5950
- generatorResult.code += `}
5990
+ result += `}
5951
5991
  `;
5992
+ }
5993
+ result += ENSURE_CLIENT_ROUTE_MODULE_CHUNK_FOR_HMR;
5994
+ }
5995
+ let hasAction = staticExports.includes("action");
5996
+ let hasLoader = staticExports.includes("loader");
5997
+ let hasComponent = staticExports.includes("default") || staticExports.includes("ServerComponent");
5998
+ let hasErrorBoundary = staticExports.includes("ErrorBoundary") || staticExports.includes("ServerErrorBoundary");
5999
+ if (isDevMode) {
6000
+ result += `export function ReactRouterHMRMeta___() {return null;};
6001
+ `;
6002
+ result += `Object.assign(ReactRouterHMRMeta___, {
6003
+ hasAction: ${JSON.stringify(hasAction)},
6004
+ hasComponent: ${JSON.stringify(hasComponent)},
6005
+ hasErrorBoundary: ${JSON.stringify(hasErrorBoundary)},
6006
+ hasLoader: ${JSON.stringify(hasLoader)},
6007
+ hasClientLoader: ${JSON.stringify(staticExports.includes("clientLoader"))},
6008
+ });
6009
+ `;
6010
+ result += `
6011
+ if (import.meta.hot) {
6012
+ `;
6013
+ result += ` import.meta.hot.accept((mod) => {
6014
+ if (typeof __reactRouterDataRouter === "object") {
6015
+ __reactRouterDataRouter._updateRoutesForHMR(new Map([[${JSON.stringify(routeId)}, {
6016
+ routeModule: mod,
6017
+ ...mod.ReactRouterHMRMeta___,
6018
+ }]]));
6019
+
6020
+ if (${chunk === "shared" ? "!mod.default || " : ""}mod.clientLoader || (
6021
+ mod.ReactRouterHMRMeta___.hasClientLoader || ReactRouterHMRMeta___.hasClientLoader || ReactRouterHMRMeta___.hasLoader
6022
+ )) {
6023
+ __reactRouterDataRouter.revalidate();
6024
+ }
6025
+ }
6026
+ });
6027
+ `;
6028
+ result += `}
6029
+ `;
6030
+ }
6031
+ return {
6032
+ code: result
6033
+ };
5952
6034
  }
5953
- if (viteCommand === "serve" && !hasClientExports) {
5954
- generatorResult.code += `
5955
- export const __ensureClientRouteModuleForHMR = true;`;
5956
- }
5957
- return generatorResult;
6035
+ return {
6036
+ name: "react-router-rsc-virtual-route-modules",
6037
+ enforce: "pre",
6038
+ async transform(_code, id) {
6039
+ const [filename2, ...rest] = id.split("?");
6040
+ const routeId = getRouteIdForFile(filename2);
6041
+ if (!routeId || shouldTransform && !shouldTransform?.(filename2)) {
6042
+ return;
6043
+ }
6044
+ let isClientEnvironment = clientEnvironments.has(this.environment.name);
6045
+ let isServerEnvironment = serverEnvironments.has(this.environment.name);
6046
+ if (!isClientEnvironment && !isServerEnvironment) {
6047
+ return;
6048
+ }
6049
+ let code = await transformToJs(_code, filename2);
6050
+ let searchParams = rest.length > 0 ? new URLSearchParams(rest.join("?")) : null;
6051
+ let clientRouteModuleType = searchParams?.get("client-route-module");
6052
+ let isServerRouteModule = searchParams?.has("server-route-module");
6053
+ if (clientRouteModuleType) {
6054
+ return await createClientRouteModuleChunk(
6055
+ id,
6056
+ code,
6057
+ clientRouteModuleType,
6058
+ routeId,
6059
+ isRootRouteModule(filename2),
6060
+ this.environment.mode === "dev"
6061
+ );
6062
+ }
6063
+ if (isServerRouteModule) {
6064
+ return createServerRouteModule(code);
6065
+ }
6066
+ if (isClientEnvironment) {
6067
+ return await createClientRouteEntry(
6068
+ id,
6069
+ code,
6070
+ isRootRouteModule(filename2),
6071
+ routeId
6072
+ );
6073
+ }
6074
+ return await createServerRouteEntry(
6075
+ id,
6076
+ code,
6077
+ isRootRouteModule(filename2),
6078
+ routeId
6079
+ );
6080
+ }
6081
+ };
6082
+ }
6083
+ function createId(id, type, value) {
6084
+ let [base, ...rest] = id.split("?");
6085
+ const searchParams = new URLSearchParams(rest.join("?"));
6086
+ searchParams.delete("client-route-module");
6087
+ searchParams.delete("server-route-module");
6088
+ searchParams.set(type, value || "");
6089
+ return `${base}?${searchParams.toString()}`;
5958
6090
  }
5959
- function parseRouteExports(code) {
6091
+ async function parseRouteExports(code) {
6092
+ await import_es_module_lexer2.init;
5960
6093
  const [, exportSpecifiers] = (0, import_es_module_lexer2.parse)(code);
5961
6094
  const staticExports = exportSpecifiers.map(({ n: name }) => name);
5962
6095
  return {
@@ -5964,27 +6097,115 @@ function parseRouteExports(code) {
5964
6097
  hasClientExports: staticExports.some(isClientRouteExport)
5965
6098
  };
5966
6099
  }
5967
- function getVirtualClientModuleId(id) {
5968
- return `${id.split("?")[0]}?client-route-module`;
6100
+ var CLIENT_NON_COMPONENT_EXPORTS2 = [
6101
+ "clientAction",
6102
+ "clientLoader",
6103
+ "clientMiddleware",
6104
+ "handle",
6105
+ "meta",
6106
+ "links",
6107
+ "shouldRevalidate"
6108
+ ];
6109
+ var CLIENT_ROUTE_EXPORTS2 = [
6110
+ ...CLIENT_NON_COMPONENT_EXPORTS2,
6111
+ "default",
6112
+ "ErrorBoundary",
6113
+ "HydrateFallback",
6114
+ "Layout"
6115
+ ];
6116
+ var CLIENT_ROUTE_EXPORTS_SET = new Set(CLIENT_ROUTE_EXPORTS2);
6117
+ function isClientRouteExport(name) {
6118
+ return CLIENT_ROUTE_EXPORTS_SET.has(name);
5969
6119
  }
5970
- function getVirtualServerModuleId(id) {
5971
- return `${id.split("?")[0]}?server-route-module`;
6120
+ var SERVER_COMPONENT_EXPORTS = [
6121
+ "ServerComponent",
6122
+ "ServerLayout",
6123
+ "ServerHydrateFallback",
6124
+ "ServerErrorBoundary"
6125
+ ];
6126
+ var SERVER_COMPONENT_EXPORTS_SET = new Set(SERVER_COMPONENT_EXPORTS);
6127
+ function isServerComponentExport(name) {
6128
+ return SERVER_COMPONENT_EXPORTS_SET.has(name);
5972
6129
  }
5973
- function isVirtualRouteModuleId(id) {
5974
- return /(\?|&)route-module(&|$)/.test(id);
6130
+ var SERVER_ROUTE_EXPORTS = [
6131
+ ...SERVER_COMPONENT_EXPORTS,
6132
+ "loader",
6133
+ "action",
6134
+ "middleware",
6135
+ "headers"
6136
+ ];
6137
+ var SERVER_ROUTE_EXPORTS_SET = new Set(SERVER_ROUTE_EXPORTS);
6138
+ function isServerRouteExport(name) {
6139
+ return SERVER_ROUTE_EXPORTS_SET.has(name);
5975
6140
  }
5976
- function isVirtualClientRouteModuleId(id) {
5977
- return /(\?|&)client-route-module(&|$)/.test(id);
6141
+ var CLIENT_MODULE_CHUNKS = /* @__PURE__ */ new Set([
6142
+ "clientAction",
6143
+ "clientLoader",
6144
+ "clientMiddleware",
6145
+ "HydrateFallback"
6146
+ ]);
6147
+ var MUTUALLY_EXCLUSIVE_ROUTE_EXPORTS = /* @__PURE__ */ new Map([
6148
+ ["ErrorBoundary", "ServerErrorBoundary"],
6149
+ ["HydrateFallback", "ServerHydrateFallback"],
6150
+ ["Layout", "ServerLayout"],
6151
+ ["default", "ServerComponent"]
6152
+ ]);
6153
+ function validateRouteModuleExports(toValidate) {
6154
+ let errors = [];
6155
+ for (let [clientExport, serverExport] of MUTUALLY_EXCLUSIVE_ROUTE_EXPORTS) {
6156
+ if (toValidate.includes(clientExport) && toValidate.includes(serverExport)) {
6157
+ errors.push([clientExport, serverExport]);
6158
+ }
6159
+ }
6160
+ if (errors.length > 0) {
6161
+ throw new Error(
6162
+ `Invalid route module exports. The following pairs of exports are mutually exclusive and cannot be exported from the same module:
6163
+ ` + errors.map(
6164
+ ([clientExport, serverExport]) => `- ${clientExport} and ${serverExport}`
6165
+ ).join("\n")
6166
+ );
6167
+ }
5978
6168
  }
5979
- function isVirtualServerRouteModuleId(id) {
5980
- return /(\?|&)server-route-module(&|$)/.test(id);
6169
+ function detectRouteChunks2(cache, id, code, isRootRouteModule) {
6170
+ function noRouteChunks() {
6171
+ return {
6172
+ chunkedExports: [],
6173
+ hasRouteChunks: false,
6174
+ hasRouteChunkByExportName: {
6175
+ clientAction: false,
6176
+ clientLoader: false,
6177
+ clientMiddleware: false,
6178
+ HydrateFallback: false
6179
+ }
6180
+ };
6181
+ }
6182
+ if (isRootRouteModule) {
6183
+ return noRouteChunks();
6184
+ }
6185
+ if (!Array.from(CLIENT_MODULE_CHUNKS).some(
6186
+ (exportName) => code.includes(exportName)
6187
+ )) {
6188
+ return noRouteChunks();
6189
+ }
6190
+ let [filename2] = id.split("?");
6191
+ return detectRouteChunks(code, cache, filename2);
5981
6192
  }
5982
- function isRootRouteFile({
6193
+ function validateRouteChunks2({
5983
6194
  id,
5984
- rootRouteFile
6195
+ valid
5985
6196
  }) {
5986
- const filePath = id.split("?")[0];
5987
- return filePath === rootRouteFile;
6197
+ let invalidChunks = Object.entries(valid).filter(([_, isValid]) => !isValid).map(([chunkName]) => chunkName);
6198
+ if (invalidChunks.length === 0) {
6199
+ return;
6200
+ }
6201
+ let plural = invalidChunks.length > 1;
6202
+ throw new Error(
6203
+ [
6204
+ `Error splitting route module: ${id}`,
6205
+ invalidChunks.map((name) => `- ${name}`).join("\n"),
6206
+ `${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.`
6207
+ ].join("\n\n")
6208
+ );
5988
6209
  }
5989
6210
 
5990
6211
  // vite/rsc/plugin.ts
@@ -6010,6 +6231,62 @@ function reactRouterRSCVitePlugin() {
6010
6231
  newConfig.routes.root.file
6011
6232
  );
6012
6233
  }
6234
+ function isRootRouteModule(id) {
6235
+ return import_pathe6.default.normalize(id) === import_pathe6.default.normalize(rootRouteFile);
6236
+ }
6237
+ function getRouteIdForFile(file) {
6238
+ let normalizedFile = import_pathe6.default.normalize(file);
6239
+ let directMatch = routeIdByFile?.get(normalizedFile);
6240
+ if (directMatch) {
6241
+ return directMatch;
6242
+ }
6243
+ return Array.from(routeIdByFile ?? []).find(
6244
+ ([routeFile]) => import_pathe6.default.normalize(routeFile).endsWith(normalizedFile)
6245
+ )?.[1];
6246
+ }
6247
+ function isMdxRouteModule(filename2) {
6248
+ let extension = import_pathe6.default.extname(filename2).toLowerCase();
6249
+ return extension === ".md" || extension === ".mdx";
6250
+ }
6251
+ function getTransformLanguage(filename2) {
6252
+ let extension = import_pathe6.default.extname(filename2).toLowerCase();
6253
+ switch (extension) {
6254
+ case ".ts":
6255
+ case ".cts":
6256
+ case ".mts":
6257
+ return "ts";
6258
+ case ".tsx":
6259
+ return "tsx";
6260
+ case ".js":
6261
+ case ".cjs":
6262
+ case ".mjs":
6263
+ case ".jsx":
6264
+ case ".md":
6265
+ case ".mdx":
6266
+ return "jsx";
6267
+ default:
6268
+ return void 0;
6269
+ }
6270
+ }
6271
+ async function transformToJs(code, filename2) {
6272
+ await preloadVite();
6273
+ let vite2 = getVite();
6274
+ let lang = getTransformLanguage(filename2);
6275
+ return ("transformWithOxc" in vite2 && typeof vite2.transformWithOxc === "function" ? await vite2.transformWithOxc(code, filename2, {
6276
+ lang,
6277
+ jsx: {
6278
+ runtime: "automatic",
6279
+ development: viteCommand !== "build",
6280
+ target: "esnext"
6281
+ }
6282
+ }) : await vite2.transformWithEsbuild(code, filename2, {
6283
+ loader: lang,
6284
+ target: "esnext",
6285
+ format: "esm",
6286
+ jsx: "automatic",
6287
+ jsxDev: viteCommand !== "build"
6288
+ })).code;
6289
+ }
6013
6290
  return [
6014
6291
  {
6015
6292
  name: "react-router/rsc",
@@ -6035,8 +6312,6 @@ function reactRouterRSCVitePlugin() {
6035
6312
  if (userConfig.serverBundles) errors.push("serverBundles");
6036
6313
  if (userConfig.future?.v8_middleware === false)
6037
6314
  errors.push("future.v8_middleware: false");
6038
- if (userConfig.future?.v8_splitRouteModules)
6039
- errors.push("future.v8_splitRouteModules");
6040
6315
  if (userConfig.future?.v8_viteEnvironmentApi === false)
6041
6316
  errors.push("future.v8_viteEnvironmentApi: false");
6042
6317
  if (userConfig.future?.unstable_subResourceIntegrity)
@@ -6199,27 +6474,6 @@ ${errors.map((x) => ` - ${x}`).join("\n")}
6199
6474
  ]
6200
6475
  }
6201
6476
  }
6202
- },
6203
- build: {
6204
- rollupOptions: {
6205
- // Copied from https://github.com/vitejs/vite-plugin-react/blob/c602225271d4acf462ba00f8d6d8a2e42492c5cd/packages/common/warning.ts
6206
- onwarn(warning, defaultHandler) {
6207
- if (warning.code === "MODULE_LEVEL_DIRECTIVE" && (warning.message.includes("use client") || warning.message.includes("use server"))) {
6208
- return;
6209
- }
6210
- if (warning.code === "SOURCEMAP_ERROR" && warning.message.includes("resolve original location") && warning.pos === 0) {
6211
- return;
6212
- }
6213
- if (viteUserConfig.build?.rollupOptions?.onwarn) {
6214
- viteUserConfig.build.rollupOptions.onwarn(
6215
- warning,
6216
- defaultHandler
6217
- );
6218
- } else {
6219
- defaultHandler(warning);
6220
- }
6221
- }
6222
- }
6223
6477
  }
6224
6478
  };
6225
6479
  },
@@ -6362,20 +6616,16 @@ ${errors.map((x) => ` - ${x}`).join("\n")}
6362
6616
  }
6363
6617
  }
6364
6618
  },
6365
- {
6366
- name: "react-router/rsc/virtual-route-modules",
6367
- transform(code, id) {
6368
- if (!routeIdByFile) return;
6369
- return transformVirtualRouteModules({
6370
- code,
6371
- id,
6372
- viteCommand,
6373
- routeIdByFile,
6374
- rootRouteFile,
6375
- viteEnvironment: this.environment
6376
- });
6377
- }
6378
- },
6619
+ virtualRouteModulesPlugin({
6620
+ environments: {
6621
+ client: ["client", "ssr"],
6622
+ server: ["rsc"]
6623
+ },
6624
+ getRouteIdForFile,
6625
+ isRootRouteModule,
6626
+ transformToJs,
6627
+ enforceSplitRouteModules: () => config.future.v8_splitRouteModules === "enforce"
6628
+ }),
6379
6629
  {
6380
6630
  name: "react-router/rsc/virtual-basename",
6381
6631
  resolveId(id) {
@@ -6417,121 +6667,21 @@ ${errors.map((x) => ` - ${x}`).join("\n")}
6417
6667
  async load(id) {
6418
6668
  if (id !== virtual2.injectHmrRuntime.resolvedId) return;
6419
6669
  return viteCommand === "serve" ? [
6420
- `import RefreshRuntime from "${virtual2.hmrRuntime.id}"`,
6421
- "RefreshRuntime.injectIntoGlobalHook(window)",
6422
- "window.$RefreshReg$ = () => {}",
6423
- "window.$RefreshSig$ = () => (type) => type",
6424
- "window.__vite_plugin_react_preamble_installed__ = true"
6670
+ `if (import.meta.hot) {
6671
+ import.meta.hot.accept();
6672
+ import.meta.hot.on('rsc:update', () => {
6673
+ // Defer revalidation to the next animation frame so React Fast Refresh
6674
+ // can apply pending client component updates first. Without this delay,
6675
+ // the RSC payload (showing updated text) can arrive and be reconciled
6676
+ // against a DOM that still has the old text, causing a hydration mismatch.
6677
+ requestAnimationFrame(() => {
6678
+ __reactRouterDataRouter.revalidate()
6679
+ });
6680
+ })
6681
+ }`
6425
6682
  ].join("\n") : "";
6426
6683
  }
6427
6684
  },
6428
- {
6429
- name: "react-router/rsc/hmr/runtime",
6430
- enforce: "pre",
6431
- resolveId(id) {
6432
- if (id === virtual2.hmrRuntime.id) return virtual2.hmrRuntime.resolvedId;
6433
- },
6434
- async load(id) {
6435
- if (id !== virtual2.hmrRuntime.resolvedId) return;
6436
- const reactRefreshDir = import_pathe6.default.dirname(
6437
- require.resolve("react-refresh/package.json")
6438
- );
6439
- const reactRefreshRuntimePath = (0, import_pathe6.join)(
6440
- reactRefreshDir,
6441
- "cjs/react-refresh-runtime.development.js"
6442
- );
6443
- return [
6444
- "const exports = {}",
6445
- await (0, import_promises4.readFile)(reactRefreshRuntimePath, "utf8"),
6446
- await (0, import_promises4.readFile)(
6447
- require.resolve("./static/rsc-refresh-utils.mjs"),
6448
- "utf8"
6449
- ),
6450
- "export default exports"
6451
- ].join("\n");
6452
- }
6453
- },
6454
- {
6455
- name: "react-router/rsc/hmr/react-refresh",
6456
- async transform(code, id, options) {
6457
- if (viteCommand !== "serve") return;
6458
- if (id.includes("/node_modules/")) return;
6459
- const filepath = id.split("?")[0];
6460
- const extensionsRE = /\.(jsx?|tsx?|mdx?)$/;
6461
- if (!extensionsRE.test(filepath)) return;
6462
- const devRuntime = "react/jsx-dev-runtime";
6463
- const ssr = options?.ssr === true;
6464
- const isJSX = filepath.endsWith("x");
6465
- const useFastRefresh = !ssr && (isJSX || code.includes(devRuntime));
6466
- if (!useFastRefresh) return;
6467
- if (isVirtualClientRouteModuleId(id)) {
6468
- const routeId = routeIdByFile?.get(filepath);
6469
- return { code: addRefreshWrapper2({ routeId, code, id }) };
6470
- }
6471
- const result = await babel2.transformAsync(code, {
6472
- babelrc: false,
6473
- configFile: false,
6474
- filename: id,
6475
- sourceFileName: filepath,
6476
- parserOpts: {
6477
- sourceType: "module",
6478
- allowAwaitOutsideFunction: true
6479
- },
6480
- plugins: [[require("react-refresh/babel"), { skipEnvCheck: true }]],
6481
- sourceMaps: true
6482
- });
6483
- if (result === null) return;
6484
- code = result.code;
6485
- const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;
6486
- if (refreshContentRE.test(code)) {
6487
- code = addRefreshWrapper2({ code, id });
6488
- }
6489
- return { code, map: result.map };
6490
- }
6491
- },
6492
- {
6493
- name: "react-router/rsc/hmr/updates",
6494
- async hotUpdate({ server, file, modules }) {
6495
- if (this.environment.name !== "rsc") return;
6496
- const clientModules = server.environments.client.moduleGraph.getModulesByFile(file);
6497
- const vite2 = await import("vite");
6498
- const isServerOnlyChange = !clientModules || clientModules.size === 0 || // Handle CSS injected from server-first routes (with ?direct query
6499
- // string) since the client graph has a reference to the CSS
6500
- vite2.isCSSRequest(file) && Array.from(clientModules).some(
6501
- (mod) => mod.id?.includes("?direct")
6502
- );
6503
- for (const mod of getModulesWithImporters(modules)) {
6504
- if (!mod.file) continue;
6505
- const normalizedPath = import_pathe6.default.normalize(mod.file);
6506
- const routeId = routeIdByFile?.get(normalizedPath);
6507
- if (routeId !== void 0) {
6508
- const routeSource = await (0, import_promises4.readFile)(normalizedPath, "utf8");
6509
- const virtualRouteModuleCode = (await server.environments.rsc.pluginContainer.transform(
6510
- routeSource,
6511
- `${normalizedPath}?route-module`
6512
- )).code;
6513
- const { staticExports } = parseRouteExports(virtualRouteModuleCode);
6514
- const hasAction = staticExports.includes("action");
6515
- const hasComponent = staticExports.includes("default");
6516
- const hasErrorBoundary = staticExports.includes("ErrorBoundary");
6517
- const hasLoader = staticExports.includes("loader");
6518
- server.hot.send({
6519
- type: "custom",
6520
- event: "react-router:hmr",
6521
- data: {
6522
- routeId,
6523
- isServerOnlyChange,
6524
- hasAction,
6525
- hasComponent,
6526
- hasErrorBoundary,
6527
- hasLoader
6528
- }
6529
- });
6530
- }
6531
- }
6532
- return modules;
6533
- }
6534
- },
6535
6685
  {
6536
6686
  name: "react-router/rsc/virtual-react-router-serve-config",
6537
6687
  resolveId(id) {
@@ -6655,7 +6805,6 @@ var virtual2 = {
6655
6805
  routeConfig: create("unstable_rsc/routes"),
6656
6806
  routeDiscovery: create("unstable_rsc/route-discovery"),
6657
6807
  injectHmrRuntime: create("unstable_rsc/inject-hmr-runtime"),
6658
- hmrRuntime: create("unstable_rsc/runtime"),
6659
6808
  basename: create("unstable_rsc/basename"),
6660
6809
  reactRouterServeConfig: create("unstable_rsc/react-router-serve-config")
6661
6810
  };
@@ -6672,65 +6821,6 @@ function invalidateVirtualModules2(viteDevServer) {
6672
6821
  function getRootDirectory(viteUserConfig) {
6673
6822
  return viteUserConfig.root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd();
6674
6823
  }
6675
- function getModulesWithImporters(modules) {
6676
- const visited = /* @__PURE__ */ new Set();
6677
- const result = /* @__PURE__ */ new Set();
6678
- function walk(module2) {
6679
- if (visited.has(module2)) return;
6680
- visited.add(module2);
6681
- result.add(module2);
6682
- for (const importer of module2.importers) {
6683
- walk(importer);
6684
- }
6685
- }
6686
- for (const module2 of modules) {
6687
- walk(module2);
6688
- }
6689
- return result;
6690
- }
6691
- function addRefreshWrapper2({
6692
- routeId,
6693
- code,
6694
- id
6695
- }) {
6696
- const acceptExports = routeId !== void 0 ? CLIENT_NON_COMPONENT_EXPORTS2 : [];
6697
- return REACT_REFRESH_HEADER2.replaceAll("__SOURCE__", JSON.stringify(id)) + code + REACT_REFRESH_FOOTER2.replaceAll("__SOURCE__", JSON.stringify(id)).replaceAll("__ACCEPT_EXPORTS__", JSON.stringify(acceptExports)).replaceAll("__ROUTE_ID__", JSON.stringify(routeId));
6698
- }
6699
- var REACT_REFRESH_HEADER2 = `
6700
- import RefreshRuntime from "${virtual2.hmrRuntime.id}";
6701
-
6702
- const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
6703
- let prevRefreshReg;
6704
- let prevRefreshSig;
6705
-
6706
- if (import.meta.hot && !inWebWorker) {
6707
- if (!window.__vite_plugin_react_preamble_installed__) {
6708
- throw new Error(
6709
- "React Router Vite plugin can't detect preamble. Something is wrong."
6710
- );
6711
- }
6712
-
6713
- prevRefreshReg = window.$RefreshReg$;
6714
- prevRefreshSig = window.$RefreshSig$;
6715
- window.$RefreshReg$ = (type, id) => {
6716
- RefreshRuntime.register(type, __SOURCE__ + " " + id)
6717
- };
6718
- window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
6719
- }`.replaceAll("\n", "");
6720
- var REACT_REFRESH_FOOTER2 = `
6721
- if (import.meta.hot && !inWebWorker) {
6722
- window.$RefreshReg$ = prevRefreshReg;
6723
- window.$RefreshSig$ = prevRefreshSig;
6724
- RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
6725
- RefreshRuntime.registerExportsForReactRefresh(__SOURCE__, currentExports);
6726
- import.meta.hot.accept((nextExports) => {
6727
- if (!nextExports) return;
6728
- __ROUTE_ID__ && window.__reactRouterRouteModuleUpdates.set(__ROUTE_ID__, nextExports);
6729
- const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(currentExports, nextExports, __ACCEPT_EXPORTS__);
6730
- if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);
6731
- });
6732
- });
6733
- }`;
6734
6824
  var getClientBuildDirectory2 = (reactRouterConfig) => import_pathe6.default.join(reactRouterConfig.buildDirectory, "client");
6735
6825
  function getPrerenderConcurrencyConfig2(reactRouterConfig) {
6736
6826
  let concurrency = 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-router/dev",
3
- "version": "7.14.0",
3
+ "version": "7.14.2",
4
4
  "description": "Dev tools and CLI for React Router",
5
5
  "homepage": "https://reactrouter.com",
6
6
  "bugs": {
@@ -92,7 +92,7 @@
92
92
  "tinyglobby": "^0.2.14",
93
93
  "valibot": "^1.2.0",
94
94
  "vite-node": "^3.2.2",
95
- "@react-router/node": "7.14.0"
95
+ "@react-router/node": "7.14.2"
96
96
  },
97
97
  "devDependencies": {
98
98
  "@types/babel__core": "^7.20.5",
@@ -116,17 +116,17 @@
116
116
  "vite": "^6.3.0",
117
117
  "wireit": "0.14.9",
118
118
  "wrangler": "^4.23.0",
119
- "@react-router/serve": "7.14.0",
120
- "react-router": "^7.14.0"
119
+ "@react-router/serve": "7.14.2",
120
+ "react-router": "^7.14.2"
121
121
  },
122
122
  "peerDependencies": {
123
123
  "@vitejs/plugin-rsc": "~0.5.21",
124
124
  "react-server-dom-webpack": "^19.2.3",
125
- "typescript": "^5.1.0",
125
+ "typescript": "^5.1.0 || ^6.0.0",
126
126
  "vite": "^5.1.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
127
127
  "wrangler": "^3.28.2 || ^4.0.0",
128
- "@react-router/serve": "^7.14.0",
129
- "react-router": "^7.14.0"
128
+ "@react-router/serve": "^7.14.2",
129
+ "react-router": "^7.14.2"
130
130
  },
131
131
  "peerDependenciesMeta": {
132
132
  "@vitejs/plugin-rsc": {