@react-router/dev 0.0.0-experimental-4b431ca46 → 0.0.0-experimental-171f8688e

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,232 +1,5 @@
1
1
  # `@remix-run/dev`
2
2
 
3
- ## 7.0.0-pre.0
4
-
5
- ### Major Changes
6
-
7
- - For Remix consumers migrating to React Router, the `vitePlugin` and `cloudflareDevProxyVitePlugin` exports have been renamed and moved. ([#11904](https://github.com/remix-run/react-router/pull/11904))
8
-
9
- ```diff
10
- -import {
11
- - vitePlugin as remix,
12
- - cloudflareDevProxyVitePlugin,
13
- -} from "@remix/dev";
14
-
15
- +import { reactRouter } from "@react-router/dev/vite";
16
- +import { cloudflareDevProxy } from "@react-router/dev/vite/cloudflare";
17
- ```
18
-
19
- - Remove single_fetch future flag. ([#11522](https://github.com/remix-run/react-router/pull/11522))
20
- - update minimum node version to 18 ([#11690](https://github.com/remix-run/react-router/pull/11690))
21
- - Add `exports` field to all packages ([#11675](https://github.com/remix-run/react-router/pull/11675))
22
- - node package no longer re-exports from react-router ([#11702](https://github.com/remix-run/react-router/pull/11702))
23
- - For Remix consumers migrating to React Router who used the Vite plugin's `buildEnd` hook, the resolved `reactRouterConfig` object no longer contains a `publicPath` property since this belongs to Vite, not React Router. ([#11575](https://github.com/remix-run/react-router/pull/11575))
24
- - For Remix consumers migrating to React Router, the Vite plugin's `manifest` option has been removed. ([#11573](https://github.com/remix-run/react-router/pull/11573))
25
-
26
- The `manifest` option been superseded by the more powerful `buildEnd` hook since it's passed the `buildManifest` argument. You can still write the build manifest to disk if needed, but you'll most likely find it more convenient to write any logic depending on the build manifest within the `buildEnd` hook itself.
27
-
28
- If you were using the `manifest` option, you can replace it with a `buildEnd` hook that writes the manifest to disk like this:
29
-
30
- ```js
31
- import { reactRouter } from "@react-router/dev/vite";
32
- import { writeFile } from "node:fs/promises";
33
-
34
- export default {
35
- plugins: [
36
- reactRouter({
37
- async buildEnd({ buildManifest }) {
38
- await writeFile(
39
- "build/manifest.json",
40
- JSON.stringify(buildManifest, null, 2),
41
- "utf-8"
42
- );
43
- },
44
- }),
45
- ],
46
- };
47
- ```
48
-
49
- - Update default `isbot` version to v5 and drop support for `isbot@3` ([#11770](https://github.com/remix-run/react-router/pull/11770))
50
-
51
- - If you have `isbot@4` or `isbot@5` in your `package.json`:
52
- - You do not need to make any changes
53
- - If you have `isbot@3` in your `package.json` and you have your own `entry.server.tsx` file in your repo
54
- - You do not need to make any changes
55
- - You can upgrade to `isbot@5` independent of the React Router v7 upgrade
56
- - If you have `isbot@3` in your `package.json` and you do not have your own `entry.server.tsx` file in your repo
57
- - You are using the internal default entry provided by React Router v7 and you will need to upgrade to `isbot@5` in your `package.json`
58
-
59
- - For Remix consumers migrating to React Router, Vite manifests (i.e. `.vite/manifest.json`) are now written within each build subdirectory, e.g. `build/client/.vite/manifest.json` and `build/server/.vite/manifest.json` instead of `build/.vite/client-manifest.json` and `build/.vite/server-manifest.json`. This means that the build output is now much closer to what you'd expect from a typical Vite project. ([#11573](https://github.com/remix-run/react-router/pull/11573))
60
-
61
- Originally the Remix Vite plugin moved all Vite manifests to a root-level `build/.vite` directory to avoid accidentally serving them in production, particularly from the client build. This was later improved with additional logic that deleted these Vite manifest files at the end of the build process unless Vite's `build.manifest` had been enabled within the app's Vite config. This greatly reduced the risk of accidentally serving the Vite manifests in production since they're only present when explicitly asked for. As a result, we can now assume that consumers will know that they need to manage these additional files themselves, and React Router can safely generate a more standard Vite build output.
62
-
63
- ### Minor Changes
64
-
65
- - Params, loader data, and action data as props for route component exports ([#11961](https://github.com/remix-run/react-router/pull/11961))
66
-
67
- ```tsx
68
- export default function Component({ params, loaderData, actionData }) {}
69
-
70
- export function HydrateFallback({ params }) {}
71
- export function ErrorBoundary({ params, loaderData, actionData }) {}
72
- ```
73
-
74
- - Remove internal entry.server.spa.tsx implementation ([#11681](https://github.com/remix-run/react-router/pull/11681))
75
- - ### Typesafety improvements ([#12019](https://github.com/remix-run/react-router/pull/12019))
76
-
77
- React Router now generates types for each of your route modules.
78
- You can access those types by importing them from `./+types/<route filename without extension>`.
79
- For example:
80
-
81
- ```ts
82
- // app/routes/product.tsx
83
- import type * as Route from "./+types/product";
84
-
85
- export function loader({ params }: Route.LoaderArgs) {}
86
-
87
- export default function Component({ loaderData }: Route.ComponentProps) {}
88
- ```
89
-
90
- This initial implementation targets type inference for:
91
-
92
- - `Params` : Path parameters from your routing config in `routes.ts` including file-based routing
93
- - `LoaderData` : Loader data from `loader` and/or `clientLoader` within your route module
94
- - `ActionData` : Action data from `action` and/or `clientAction` within your route module
95
-
96
- These types are then used to create types for route export args and props:
97
-
98
- - `LoaderArgs`
99
- - `ClientLoaderArgs`
100
- - `ActionArgs`
101
- - `ClientActionArgs`
102
- - `HydrateFallbackProps`
103
- - `ComponentProps` (for the `default` export)
104
- - `ErrorBoundaryProps`
105
-
106
- In the future, we plan to add types for the rest of the route module exports: `meta`, `links`, `headers`, `shouldRevalidate`, etc.
107
- We also plan to generate types for typesafe `Link`s:
108
-
109
- ```tsx
110
- <Link to="/products/:id" params={{ id: 1 }} />
111
- // ^^^^^^^^^^^^^ ^^^^^^^^^
112
- // typesafe `to` and `params` based on the available routes in your app
113
- ```
114
-
115
- #### Setup
116
-
117
- React Router will generate types into a `.react-router/` directory at the root of your app.
118
- This directory is fully managed by React Router and is derived based on your route config (`routes.ts`).
119
-
120
- 👉 **Add `.react-router/` to `.gitignore`**
121
-
122
- ```txt
123
- .react-router
124
- ```
125
-
126
- You should also ensure that generated types for routes are always present before running typechecking,
127
- especially for running typechecking in CI.
128
-
129
- 👉 **Add `react-router typegen` to your `typecheck` command in `package.json`**
130
-
131
- ```json
132
- {
133
- "scripts": {
134
- "typecheck": "react-router typegen && tsc"
135
- }
136
- }
137
- ```
138
-
139
- To get TypeScript to use those generated types, you'll need to add them to `include` in `tsconfig.json`.
140
- And to be able to import them as if they files next to your route modules, you'll also need to configure `rootDirs`.
141
-
142
- 👉 **Configure `tsconfig.json` for generated types**
143
-
144
- ```json
145
- {
146
- "include": [".react-router/types/**/*"],
147
- "compilerOptions": {
148
- "rootDirs": [".", "./.react-router/types"]
149
- }
150
- }
151
- ```
152
-
153
- #### `typegen` command
154
-
155
- You can manually generate types with the new `typegen` command:
156
-
157
- ```sh
158
- react-router typegen
159
- ```
160
-
161
- However, manual type generation is tedious and types can get out of sync quickly if you ever forget to run `typegen`.
162
- Instead, we recommend that you setup our new TypeScript plugin which will automatically generate fresh types whenever routes change.
163
- That way, you'll always have up-to-date types.
164
-
165
- #### TypeScript plugin
166
-
167
- To get automatic type generation, you can use our new TypeScript plugin.
168
-
169
- 👉 **Add the TypeScript plugin to `tsconfig.json`**
170
-
171
- ```json
172
- {
173
- "compilerOptions": {
174
- "plugins": [{ "name": "@react-router/dev" }]
175
- }
176
- }
177
- ```
178
-
179
- We plan to add some other goodies to our TypeScript plugin soon, including:
180
-
181
- - Automatic `jsdoc` for route exports that include links to official docs
182
- - Autocomplete for route exports
183
- - Warnings for non-HMR compliant exports
184
-
185
- ##### VSCode
186
-
187
- TypeScript looks for plugins registered in `tsconfig.json` in the local `node_modules/`,
188
- but VSCode ships with its own copy of TypeScript that is installed outside of your project.
189
- For TypeScript plugins to work, you'll need to tell VSCode to use the local workspace version of TypeScript.
190
- For security reasons, [VSCode won't use the workspace version of TypeScript](https://code.visualstudio.com/docs/typescript/typescript-compiling#_using-the-workspace-version-of-typescript) until you manually opt-in.
191
-
192
- Your project should have a `.vscode/settings.json` with the following settings:
193
-
194
- ```json
195
- {
196
- "typescript.tsdk": "node_modules/typescript/lib",
197
- "typescript.enablePromptUseWorkspaceTsdk": true
198
- }
199
- ```
200
-
201
- That way [VSCode will ask you](https://code.visualstudio.com/updates/v1_45#_prompt-users-to-switch-to-the-workspace-version-of-typescript) if you want to use the workspace version of TypeScript the first time you open a TS file in that project.
202
-
203
- > [!IMPORTANT]
204
- > You'll need to install dependencies first so that the workspace version of TypeScript is available.
205
-
206
- 👉 **Select "Allow" when VSCode asks if you want to use the workspace version of TypeScript**
207
-
208
- Otherwise, you can also manually opt-in to the workspace version:
209
-
210
- 1. Open up any TypeScript file in your project
211
- 2. Open up the VSCode Command Palette (<kbd>Cmd</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>)
212
- 3. Search for `Select TypeScript Version`
213
- 4. Choose `Use Workspace Version`
214
- 5. Quit and reopen VSCode
215
-
216
- ##### Troubleshooting
217
-
218
- In VSCode, open up any TypeScript file in your project and then use <kbd>CMD</kbd>+<kbd>SHIFT</kbd>+<kbd>P</kbd> to select `Open TS Server log`.
219
- There should be a log for `[react-router] setup` that indicates that the plugin was resolved correctly.
220
- Then look for any errors in the log.
221
-
222
- ### Patch Changes
223
-
224
- - include root "react-dom" module for optimization ([#12060](https://github.com/remix-run/react-router/pull/12060))
225
- - Updated dependencies:
226
- - `react-router@7.0.0-pre.0`
227
- - `@react-router/serve@7.0.0-pre.0`
228
- - `@react-router/node@7.0.0-pre.0`
229
-
230
3
  ## 2.9.0
231
4
 
232
5
  ### Minor Changes
package/README.md CHANGED
@@ -1,13 +1,7 @@
1
- # Welcome to Remix!
1
+ # @react-router/dev
2
2
 
3
- [Remix](https://remix.run) is a web framework that helps you build better websites with React.
4
-
5
- To get started, open a new shell and run:
3
+ Dev tools and CLI for [React Router.](https://github.com/remix-run/react-router)
6
4
 
7
5
  ```sh
8
- npx create-remix@latest
6
+ npm install @react-router/dev
9
7
  ```
10
-
11
- Then follow the prompts you see in your terminal.
12
-
13
- For more information about Remix, [visit remix.run](https://remix.run)!
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/cli/run.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -98,8 +98,9 @@ ${colors.logoBlue("react-router")}
98
98
  async function run(argv = process.argv.slice(2)) {
99
99
  // Check the node version
100
100
  let versions = process.versions;
101
- if (versions && versions.node && semver__default["default"].major(versions.node) < 18) {
102
- throw new Error(`️🚨 Oops, Node v${versions.node} detected. react-router requires a Node version greater than 18.`);
101
+ let MINIMUM_NODE_VERSION = 20;
102
+ if (versions && versions.node && semver__default["default"].major(versions.node) < MINIMUM_NODE_VERSION) {
103
+ throw new Error(`️🚨 Oops, Node v${versions.node} detected. react-router requires ` + `a Node version greater than ${MINIMUM_NODE_VERSION}.`);
103
104
  }
104
105
  let isBooleanFlag = arg => {
105
106
  let index = argv.indexOf(arg);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/colors.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -91,35 +91,39 @@ type CreateRouteOptions = Pick<RouteConfigEntry, (typeof createConfigRouteOption
91
91
  * Helper function for creating a route config entry, for use within
92
92
  * `routes.ts`.
93
93
  */
94
- declare function createRoute(path: string | null | undefined, file: string, children?: RouteConfigEntry[]): RouteConfigEntry;
95
- declare function createRoute(path: string | null | undefined, file: string, options: CreateRouteOptions, children?: RouteConfigEntry[]): RouteConfigEntry;
94
+ declare function route(path: string | null | undefined, file: string, children?: RouteConfigEntry[]): RouteConfigEntry;
95
+ declare function route(path: string | null | undefined, file: string, options: CreateRouteOptions, children?: RouteConfigEntry[]): RouteConfigEntry;
96
96
  declare const createIndexOptionKeys: ["id"];
97
97
  type CreateIndexOptions = Pick<RouteConfigEntry, (typeof createIndexOptionKeys)[number]>;
98
98
  /**
99
99
  * Helper function for creating a route config entry for an index route, for use
100
100
  * within `routes.ts`.
101
101
  */
102
- declare function createIndex(file: string, options?: CreateIndexOptions): RouteConfigEntry;
102
+ declare function index(file: string, options?: CreateIndexOptions): RouteConfigEntry;
103
103
  declare const createLayoutOptionKeys: ["id"];
104
104
  type CreateLayoutOptions = Pick<RouteConfigEntry, (typeof createLayoutOptionKeys)[number]>;
105
105
  /**
106
106
  * Helper function for creating a route config entry for a layout route, for use
107
107
  * within `routes.ts`.
108
108
  */
109
- declare function createLayout(file: string, children?: RouteConfigEntry[]): RouteConfigEntry;
110
- declare function createLayout(file: string, options: CreateLayoutOptions, children?: RouteConfigEntry[]): RouteConfigEntry;
111
- export declare const route: typeof createRoute;
112
- export declare const index: typeof createIndex;
113
- export declare const layout: typeof createLayout;
109
+ declare function layout(file: string, children?: RouteConfigEntry[]): RouteConfigEntry;
110
+ declare function layout(file: string, options: CreateLayoutOptions, children?: RouteConfigEntry[]): RouteConfigEntry;
114
111
  /**
115
- * Creates a set of route config helpers that resolve file paths relative to the
116
- * given directory, for use within `routes.ts`. This is designed to support
117
- * splitting route config into multiple files within different directories.
112
+ * Helper function for adding a path prefix to a set of routes without needing
113
+ * to introduce a parent route file, for use within `routes.ts`.
118
114
  */
119
- export declare function relative(directory: string): {
115
+ declare function prefix(prefixPath: string, routes: RouteConfigEntry[]): RouteConfigEntry[];
116
+ declare const helpers: {
120
117
  route: typeof route;
121
118
  index: typeof index;
122
119
  layout: typeof layout;
120
+ prefix: typeof prefix;
123
121
  };
122
+ export { route, index, layout, prefix };
123
+ /**
124
+ * Creates a set of route config helpers that resolve file paths relative to the
125
+ * given directory, for use within `routes.ts`. This is designed to support
126
+ * splitting route config into multiple files within different directories.
127
+ */
128
+ export declare function relative(directory: string): typeof helpers;
124
129
  export declare function configRoutesToRouteManifest(routes: RouteConfigEntry[], rootId?: string): RouteManifest;
125
- export {};
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -97,7 +97,7 @@ function validateRouteConfig({
97
97
  };
98
98
  }
99
99
  const createConfigRouteOptionKeys = ["id", "index", "caseSensitive"];
100
- function createRoute(path, file, optionsOrChildren, children) {
100
+ function route(path, file, optionsOrChildren, children) {
101
101
  let options = {};
102
102
  if (Array.isArray(optionsOrChildren) || !optionsOrChildren) {
103
103
  children = optionsOrChildren;
@@ -116,7 +116,7 @@ const createIndexOptionKeys = ["id"];
116
116
  * Helper function for creating a route config entry for an index route, for use
117
117
  * within `routes.ts`.
118
118
  */
119
- function createIndex(file, options) {
119
+ function index(file, options) {
120
120
  return {
121
121
  file,
122
122
  index: true,
@@ -124,7 +124,7 @@ function createIndex(file, options) {
124
124
  };
125
125
  }
126
126
  const createLayoutOptionKeys = ["id"];
127
- function createLayout(file, optionsOrChildren, children) {
127
+ function layout(file, optionsOrChildren, children) {
128
128
  let options = {};
129
129
  if (Array.isArray(optionsOrChildren) || !optionsOrChildren) {
130
130
  children = optionsOrChildren;
@@ -137,9 +137,27 @@ function createLayout(file, optionsOrChildren, children) {
137
137
  ...pick__default["default"](options, createLayoutOptionKeys)
138
138
  };
139
139
  }
140
- const route = createRoute;
141
- const index = createIndex;
142
- const layout = createLayout;
140
+ /**
141
+ * Helper function for adding a path prefix to a set of routes without needing
142
+ * to introduce a parent route file, for use within `routes.ts`.
143
+ */
144
+ function prefix(prefixPath, routes) {
145
+ return routes.map(route => {
146
+ if (route.index || typeof route.path === "string") {
147
+ return {
148
+ ...route,
149
+ path: route.path ? joinRoutePaths(prefixPath, route.path) : prefixPath,
150
+ children: route.children
151
+ };
152
+ } else if (route.children) {
153
+ return {
154
+ ...route,
155
+ children: prefix(prefixPath, route.children)
156
+ };
157
+ }
158
+ return route;
159
+ });
160
+ }
143
161
  /**
144
162
  * Creates a set of route config helpers that resolve file paths relative to the
145
163
  * given directory, for use within `routes.ts`. This is designed to support
@@ -173,7 +191,10 @@ function relative(directory) {
173
191
  */
174
192
  layout: (file, ...rest) => {
175
193
  return layout(path.resolve(directory, file), ...rest);
176
- }
194
+ },
195
+ // Passthrough of helper functions that don't need relative scoping so that
196
+ // a complete API is still provided.
197
+ prefix
177
198
  };
178
199
  }
179
200
  function configRoutesToRouteManifest(routes, rootId = "root") {
@@ -212,11 +233,18 @@ function normalizeSlashes(file) {
212
233
  function stripFileExtension(file) {
213
234
  return file.replace(/\.[a-z0-9]+$/i, "");
214
235
  }
236
+ function joinRoutePaths(path1, path2) {
237
+ return [path1.replace(/\/+$/, ""),
238
+ // Remove trailing slashes
239
+ path2.replace(/^\/+/, "") // Remove leading slashes
240
+ ].join("/");
241
+ }
215
242
 
216
243
  exports.configRoutesToRouteManifest = configRoutesToRouteManifest;
217
244
  exports.getAppDirectory = getAppDirectory;
218
245
  exports.index = index;
219
246
  exports.layout = layout;
247
+ exports.prefix = prefix;
220
248
  exports.relative = relative;
221
249
  exports.resolvedRouteConfigSchema = resolvedRouteConfigSchema;
222
250
  exports.route = route;
package/dist/invariant.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -12,7 +12,7 @@
12
12
 
13
13
  function invariant(value, message) {
14
14
  if (value === false || value === null || typeof value === "undefined") {
15
- console.error("The following error is a bug in Remix; please open an issue! https://github.com/remix-run/remix/issues/new");
15
+ console.error("The following error is a bug in React Router; please open an issue! https://github.com/remix-run/react-router/issues/new/choose");
16
16
  throw new Error(message);
17
17
  }
18
18
  }
package/dist/routes.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export type { RouteConfig, RouteConfigEntry } from "./config/routes";
2
- export { route, index, layout, relative, getAppDirectory, } from "./config/routes";
2
+ export { route, index, layout, prefix, relative, getAppDirectory, } from "./config/routes";
package/dist/routes.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -19,5 +19,6 @@ var routes = require('./config/routes.js');
19
19
  exports.getAppDirectory = routes.getAppDirectory;
20
20
  exports.index = routes.index;
21
21
  exports.layout = routes.layout;
22
+ exports.prefix = routes.prefix;
22
23
  exports.relative = routes.relative;
23
24
  exports.route = routes.route;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -74,10 +74,10 @@ async function watch(rootDirectory) {
74
74
  }
75
75
  routesViteNodeContext.devServer.moduleGraph.invalidateAll();
76
76
  routesViteNodeContext.runner.moduleCache.clear();
77
- const result = await routesViteNodeContext.runner.executeFile(routesTsPath);
77
+ const routeConfig = (await routesViteNodeContext.runner.executeFile(routesTsPath)).routes;
78
78
  return {
79
79
  ...routes$1,
80
- ...routes.configRoutesToRouteManifest(result.routes)
80
+ ...routes.configRoutesToRouteManifest(await routeConfig)
81
81
  };
82
82
  }
83
83
  const ctx = {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/vite/dev.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -41,12 +41,20 @@ function fromNodeRequest(nodeReq, nodeRes) {
41
41
  let url = new URL(nodeReq.originalUrl, origin);
42
42
  // Abort action/loaders once we can no longer write a response
43
43
  let controller = new AbortController();
44
- nodeRes.on("close", () => controller.abort());
45
44
  let init = {
46
45
  method: nodeReq.method,
47
46
  headers: fromNodeHeaders(nodeReq.headers),
48
47
  signal: controller.signal
49
48
  };
49
+ // Abort action/loaders once we can no longer write a response iff we have
50
+ // not yet sent a response (i.e., `close` without `finish`)
51
+ // `finish` -> done rendering the response
52
+ // `close` -> response can no longer be written to
53
+ nodeRes.on("finish", () => controller = null);
54
+ nodeRes.on("close", () => {
55
+ var _controller;
56
+ return (_controller = controller) === null || _controller === void 0 ? void 0 : _controller.abort();
57
+ });
50
58
  if (nodeReq.method !== "GET" && nodeReq.method !== "HEAD") {
51
59
  init.body = node.createReadableStreamFromReadable(nodeReq);
52
60
  init.duplex = "half";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1155,20 +1155,28 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
1155
1155
  } else {
1156
1156
  routesToPrerender = reactRouterConfig.prerender || ["/"];
1157
1157
  }
1158
- let requestInit = {
1159
- headers: {
1160
- // Header that can be used in the loader to know if you're running at
1161
- // build time or runtime
1162
- "X-React-Router-Prerender": "yes"
1163
- }
1158
+ let headers = {
1159
+ // Header that can be used in the loader to know if you're running at
1160
+ // build time or runtime
1161
+ "X-React-Router-Prerender": "yes"
1164
1162
  };
1165
1163
  for (let path of routesToPrerender) {
1166
1164
  var _matchRoutes;
1167
1165
  let hasLoaders = (_matchRoutes = reactRouter.matchRoutes(routes, path)) === null || _matchRoutes === void 0 ? void 0 : _matchRoutes.some(m => m.route.loader);
1166
+ let data;
1168
1167
  if (hasLoaders) {
1169
- await prerenderData(handler, path, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit);
1168
+ data = await prerenderData(handler, path, clientBuildDirectory, reactRouterConfig, viteConfig, {
1169
+ headers
1170
+ });
1170
1171
  }
1171
- await prerenderRoute(handler, path, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit);
1172
+ await prerenderRoute(handler, path, clientBuildDirectory, reactRouterConfig, viteConfig, data ? {
1173
+ headers: {
1174
+ ...headers,
1175
+ "X-React-Router-Prerender-Data": data
1176
+ }
1177
+ } : {
1178
+ headers
1179
+ });
1172
1180
  }
1173
1181
  await prerenderManifest(build, clientBuildDirectory, reactRouterConfig, viteConfig);
1174
1182
  }
@@ -1194,8 +1202,8 @@ function determineStaticPrerenderRoutes(routes, viteConfig, isBooleanUsage = fal
1194
1202
  }
1195
1203
  }
1196
1204
  recurse(routes);
1197
- if (isBooleanUsage && paramRoutes) {
1198
- viteConfig.logger.warn("The following paths were not prerendered because Dynamic Param and Splat " + "routes cannot be prerendered when using `prerender:true`. You may want to " + "consider using the `prerender()` API if you wish to prerender slug and " + "splat routes.");
1205
+ if (isBooleanUsage && paramRoutes.length > 0) {
1206
+ viteConfig.logger.warn(["⚠️ 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:", ...paramRoutes.map(p => " - " + p)].join("\n"));
1199
1207
  }
1200
1208
  // Clean double slashes and remove trailing slashes
1201
1209
  return paths.map(p => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1"));
@@ -1212,6 +1220,7 @@ async function prerenderData(handler, prerenderPath, clientBuildDirectory, react
1212
1220
  await fse__namespace.ensureDir(path__namespace.dirname(outfile));
1213
1221
  await fse__namespace.outputFile(outfile, data);
1214
1222
  viteConfig.logger.info(`Prerender: Generated ${colors__default["default"].bold(outfile)}`);
1223
+ return data;
1215
1224
  }
1216
1225
  async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
1217
1226
  let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(/\/\/+/g, "/");
@@ -1252,11 +1261,13 @@ function validatePrerenderedHtml(html, prefix) {
1252
1261
  function groupRoutesByParentId(manifest) {
1253
1262
  let routes = {};
1254
1263
  Object.values(manifest).forEach(route => {
1255
- let parentId = route.parentId || "";
1256
- if (!routes[parentId]) {
1257
- routes[parentId] = [];
1264
+ if (route) {
1265
+ let parentId = route.parentId || "";
1266
+ if (!routes[parentId]) {
1267
+ routes[parentId] = [];
1268
+ }
1269
+ routes[parentId].push(route);
1258
1270
  }
1259
- routes[parentId].push(route);
1260
1271
  });
1261
1272
  return routes;
1262
1273
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -49,21 +49,21 @@ const enqueueUpdate = debounce(async () => {
49
49
  .map((route) => route.id)
50
50
  );
51
51
 
52
- let routes = __reactRouterInstance.createRoutesForHMR(
52
+ let routes = __reactRouterDataRouter.createRoutesForHMR(
53
53
  needsRevalidation,
54
54
  manifest.routes,
55
55
  window.__reactRouterRouteModules,
56
56
  window.__reactRouterContext.future,
57
57
  window.__reactRouterContext.isSpaMode
58
58
  );
59
- __reactRouterInstance._internalSetRoutes(routes);
59
+ __reactRouterDataRouter._internalSetRoutes(routes);
60
60
  routeUpdates.clear();
61
61
  window.__reactRouterRouteModuleUpdates.clear();
62
62
  }
63
63
 
64
64
  try {
65
65
  window.__reactRouterHdrActive = true;
66
- await __reactRouterInstance.revalidate();
66
+ await __reactRouterDataRouter.revalidate();
67
67
  } finally {
68
68
  window.__reactRouterHdrActive = false;
69
69
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -147,11 +147,13 @@ const findDeps = async (vite, node, deps) => {
147
147
  const groupRoutesByParentId = manifest => {
148
148
  let routes = {};
149
149
  Object.values(manifest).forEach(route => {
150
- let parentId = route.parentId || "";
151
- if (!routes[parentId]) {
152
- routes[parentId] = [];
150
+ if (route) {
151
+ let parentId = route.parentId || "";
152
+ if (!routes[parentId]) {
153
+ routes[parentId] = [];
154
+ }
155
+ routes[parentId].push(route);
153
156
  }
154
- routes[parentId].push(route);
155
157
  });
156
158
  return routes;
157
159
  };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/vite/vmod.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
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-4b431ca46
2
+ * @react-router/dev v0.0.0-experimental-171f8688e
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-4b431ca46",
3
+ "version": "0.0.0-experimental-171f8688e",
4
4
  "description": "Dev tools and CLI for React Router",
5
5
  "homepage": "https://reactrouter.com",
6
6
  "bugs": {
@@ -61,7 +61,7 @@
61
61
  "set-cookie-parser": "^2.6.0",
62
62
  "valibot": "^0.41.0",
63
63
  "vite-node": "^1.6.0",
64
- "@react-router/node": "0.0.0-experimental-4b431ca46"
64
+ "@react-router/node": "0.0.0-experimental-171f8688e"
65
65
  },
66
66
  "devDependencies": {
67
67
  "@types/babel__core": "^7.20.5",
@@ -87,15 +87,15 @@
87
87
  "tiny-invariant": "^1.2.0",
88
88
  "vite": "^5.1.0",
89
89
  "wrangler": "^3.28.2",
90
- "react-router": "^0.0.0-experimental-4b431ca46",
91
- "@react-router/serve": "0.0.0-experimental-4b431ca46"
90
+ "@react-router/serve": "0.0.0-experimental-171f8688e",
91
+ "react-router": "^0.0.0-experimental-171f8688e"
92
92
  },
93
93
  "peerDependencies": {
94
94
  "typescript": "^5.1.0",
95
95
  "vite": "^5.1.0",
96
96
  "wrangler": "^3.28.2",
97
- "@react-router/serve": "^0.0.0-experimental-4b431ca46",
98
- "react-router": "^0.0.0-experimental-4b431ca46"
97
+ "react-router": "^0.0.0-experimental-171f8688e",
98
+ "@react-router/serve": "^0.0.0-experimental-171f8688e"
99
99
  },
100
100
  "peerDependenciesMeta": {
101
101
  "@react-router/serve": {
@@ -109,7 +109,7 @@
109
109
  }
110
110
  },
111
111
  "engines": {
112
- "node": ">=18.0.0"
112
+ "node": ">=20.0.0"
113
113
  },
114
114
  "files": [
115
115
  "dist/",