react-router 8.0.0-pre.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/dist/development/dom-export.js +1 -1
- package/dist/development/index-react-server-client.js +1 -1
- package/dist/development/index-react-server.d.ts +9 -2
- package/dist/development/index-react-server.js +91 -88
- package/dist/development/index.d.ts +1 -2
- package/dist/development/index.js +2 -3
- package/dist/development/lib/actions.js +6 -18
- package/dist/development/lib/components.d.ts +11 -3
- package/dist/development/lib/components.js +8 -2
- package/dist/development/lib/context.js +1 -1
- package/dist/development/lib/dom/dom.js +1 -1
- package/dist/development/lib/dom/lib.d.ts +12 -1
- package/dist/development/lib/dom/lib.js +18 -6
- package/dist/development/lib/dom/server.js +2 -2
- package/dist/development/lib/dom/ssr/components.d.ts +4 -2
- package/dist/development/lib/dom/ssr/components.js +13 -3
- package/dist/development/lib/dom/ssr/data.js +1 -1
- package/dist/development/lib/dom/ssr/entry.d.ts +1 -0
- package/dist/development/lib/dom/ssr/errorBoundaries.js +7 -3
- package/dist/development/lib/dom/ssr/fallback.js +8 -3
- package/dist/development/lib/dom/ssr/fog-of-war.js +12 -2
- package/dist/development/lib/dom/ssr/hydration.js +1 -1
- package/dist/development/lib/dom/ssr/invariant.js +1 -1
- package/dist/development/lib/dom/ssr/links.js +1 -1
- package/dist/development/lib/dom/ssr/markup.js +1 -1
- package/dist/development/lib/dom/ssr/routeModules.js +1 -1
- package/dist/development/lib/dom/ssr/routes-test-stub.js +1 -1
- package/dist/development/lib/dom/ssr/routes.js +1 -1
- package/dist/development/lib/dom/ssr/server.d.ts +4 -1
- package/dist/development/lib/dom/ssr/server.js +2 -1
- package/dist/development/lib/dom/ssr/single-fetch.js +2 -3
- package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/development/lib/dom-export/hydrated-router.d.ts +1 -1
- package/dist/development/lib/dom-export/hydrated-router.js +14 -17
- package/dist/development/lib/errors.js +1 -1
- package/dist/development/lib/hooks.js +6 -4
- package/dist/development/lib/href.js +1 -1
- package/dist/development/lib/router/history.js +3 -2
- package/dist/development/lib/router/instrumentation.js +1 -1
- package/dist/development/lib/router/links.d.ts +3 -2
- package/dist/development/lib/router/router.js +13 -6
- package/dist/development/lib/router/url.js +18 -0
- package/dist/development/lib/router/utils.d.ts +6 -0
- package/dist/development/lib/router/utils.js +27 -8
- package/dist/development/lib/rsc/browser.js +21 -17
- package/dist/development/lib/rsc/errorBoundaries.js +1 -1
- package/dist/development/lib/rsc/html-stream/browser.js +1 -1
- package/dist/development/lib/rsc/html-stream/server.js +1 -1
- package/dist/development/lib/rsc/route-modules.js +1 -1
- package/dist/development/lib/rsc/server.ssr.js +27 -11
- package/dist/development/lib/server-runtime/cookies.js +1 -1
- package/dist/development/lib/server-runtime/crypto.js +1 -1
- package/dist/development/lib/server-runtime/data.js +1 -1
- package/dist/development/lib/server-runtime/dev.js +1 -1
- package/dist/development/lib/server-runtime/entry.js +1 -1
- package/dist/development/lib/server-runtime/errors.js +2 -22
- package/dist/development/lib/server-runtime/headers.js +1 -1
- package/dist/development/lib/server-runtime/invariant.js +1 -1
- package/dist/development/lib/server-runtime/mode.js +1 -1
- package/dist/development/lib/server-runtime/routeMatching.js +1 -1
- package/dist/development/lib/server-runtime/routes.js +1 -1
- package/dist/development/lib/server-runtime/server.js +17 -23
- package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/development/lib/server-runtime/sessions/cookieStorage.js +1 -1
- package/dist/development/lib/server-runtime/sessions/memoryStorage.js +1 -1
- package/dist/development/lib/server-runtime/sessions.js +1 -1
- package/dist/development/lib/server-runtime/single-fetch.js +4 -4
- package/dist/development/lib/server-runtime/urls.js +2 -5
- package/dist/development/lib/server-runtime/warnings.js +1 -1
- package/dist/development/lib/types/internal.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +2 -1
- package/dist/development/vendor/turbo-stream-v2/unflatten.js +3 -2
- package/dist/development/vendor/turbo-stream-v2/utils.js +2 -10
- package/dist/production/dom-export.js +1 -1
- package/dist/production/index-react-server-client.js +1 -1
- package/dist/production/index-react-server.d.ts +9 -2
- package/dist/production/index-react-server.js +91 -88
- package/dist/production/index.d.ts +1 -2
- package/dist/production/index.js +2 -3
- package/dist/production/lib/actions.js +6 -18
- package/dist/production/lib/components.d.ts +11 -3
- package/dist/production/lib/components.js +8 -2
- package/dist/production/lib/context.js +1 -1
- package/dist/production/lib/dom/dom.js +1 -1
- package/dist/production/lib/dom/lib.d.ts +12 -1
- package/dist/production/lib/dom/lib.js +18 -6
- package/dist/production/lib/dom/server.js +2 -2
- package/dist/production/lib/dom/ssr/components.d.ts +4 -2
- package/dist/production/lib/dom/ssr/components.js +13 -3
- package/dist/production/lib/dom/ssr/data.js +1 -1
- package/dist/production/lib/dom/ssr/entry.d.ts +1 -0
- package/dist/production/lib/dom/ssr/errorBoundaries.js +7 -3
- package/dist/production/lib/dom/ssr/fallback.js +3 -1
- package/dist/production/lib/dom/ssr/fog-of-war.js +12 -2
- package/dist/production/lib/dom/ssr/hydration.js +1 -1
- package/dist/production/lib/dom/ssr/invariant.js +1 -1
- package/dist/production/lib/dom/ssr/links.js +1 -1
- package/dist/production/lib/dom/ssr/markup.js +1 -1
- package/dist/production/lib/dom/ssr/routeModules.js +1 -1
- package/dist/production/lib/dom/ssr/routes-test-stub.js +1 -1
- package/dist/production/lib/dom/ssr/routes.js +1 -1
- package/dist/production/lib/dom/ssr/server.d.ts +4 -1
- package/dist/production/lib/dom/ssr/server.js +2 -1
- package/dist/production/lib/dom/ssr/single-fetch.js +2 -3
- package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/production/lib/dom-export/hydrated-router.d.ts +1 -1
- package/dist/production/lib/dom-export/hydrated-router.js +14 -17
- package/dist/production/lib/errors.js +1 -1
- package/dist/production/lib/hooks.js +6 -4
- package/dist/production/lib/href.js +1 -1
- package/dist/production/lib/router/history.js +3 -2
- package/dist/production/lib/router/instrumentation.js +1 -1
- package/dist/production/lib/router/links.d.ts +3 -2
- package/dist/production/lib/router/router.js +13 -6
- package/dist/production/lib/router/url.js +18 -0
- package/dist/production/lib/router/utils.d.ts +6 -0
- package/dist/production/lib/router/utils.js +27 -8
- package/dist/production/lib/rsc/browser.js +21 -17
- package/dist/production/lib/rsc/errorBoundaries.js +1 -1
- package/dist/production/lib/rsc/html-stream/browser.js +1 -1
- package/dist/production/lib/rsc/html-stream/server.js +1 -1
- package/dist/production/lib/rsc/route-modules.js +1 -1
- package/dist/production/lib/rsc/server.ssr.js +27 -11
- package/dist/production/lib/server-runtime/cookies.js +1 -1
- package/dist/production/lib/server-runtime/crypto.js +1 -1
- package/dist/production/lib/server-runtime/data.js +1 -1
- package/dist/production/lib/server-runtime/dev.js +1 -1
- package/dist/production/lib/server-runtime/entry.js +1 -1
- package/dist/production/lib/server-runtime/errors.js +2 -22
- package/dist/production/lib/server-runtime/headers.js +1 -1
- package/dist/production/lib/server-runtime/invariant.js +1 -1
- package/dist/production/lib/server-runtime/mode.js +1 -1
- package/dist/production/lib/server-runtime/routeMatching.js +1 -1
- package/dist/production/lib/server-runtime/routes.js +1 -1
- package/dist/production/lib/server-runtime/server.js +17 -23
- package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/production/lib/server-runtime/sessions/cookieStorage.js +1 -1
- package/dist/production/lib/server-runtime/sessions/memoryStorage.js +1 -1
- package/dist/production/lib/server-runtime/sessions.js +1 -1
- package/dist/production/lib/server-runtime/single-fetch.js +4 -4
- package/dist/production/lib/server-runtime/urls.js +2 -5
- package/dist/production/lib/server-runtime/warnings.js +1 -1
- package/dist/production/lib/types/internal.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +2 -1
- package/dist/production/vendor/turbo-stream-v2/unflatten.js +3 -2
- package/dist/production/vendor/turbo-stream-v2/utils.js +2 -10
- package/docs/explanation/code-splitting.md +1 -1
- package/docs/explanation/index-query-param.md +2 -2
- package/docs/explanation/type-safety.md +1 -1
- package/docs/how-to/data-strategy.md +5 -5
- package/docs/how-to/error-reporting.md +10 -2
- package/docs/how-to/headers.md +2 -1
- package/docs/how-to/middleware.md +8 -89
- package/docs/how-to/security.md +9 -7
- package/docs/how-to/status.md +1 -1
- package/docs/index.md +3 -6
- package/docs/start/data/installation.md +4 -0
- package/docs/start/data/route-object.md +20 -0
- package/docs/start/framework/actions.md +0 -1
- package/docs/start/framework/data-loading.md +1 -1
- package/docs/start/framework/deploying.md +4 -0
- package/docs/start/framework/installation.md +0 -1
- package/docs/start/modes.md +1 -2
- package/docs/upgrading/component-routes.md +2 -2
- package/docs/upgrading/future.md +58 -11
- package/docs/upgrading/router-provider.md +6 -3
- package/docs/upgrading/v7.md +443 -0
- package/package.json +7 -7
- package/dist/development/lib/dom/ssr/errors.d.ts +0 -7
- package/dist/development/lib/dom/ssr/errors.js +0 -36
- package/dist/production/lib/dom/ssr/errors.d.ts +0 -7
- package/dist/production/lib/dom/ssr/errors.js +0 -36
- package/docs/upgrading/remix.md +0 -403
- package/docs/upgrading/v6.md +0 -379
|
@@ -94,3 +94,7 @@ Netlify maintains their own template for React Router. Checkout the [Netlify Gui
|
|
|
94
94
|
### EdgeOne Pages
|
|
95
95
|
|
|
96
96
|
EdgeOne Pages maintains their own template for React Router. Checkout the [EdgeOne Pages Guide](https://pages.edgeone.ai/document/framework-react-router) for more information.
|
|
97
|
+
|
|
98
|
+
### DeployHQ
|
|
99
|
+
|
|
100
|
+
DeployHQ maintains their own guide for deploying React Router to your own server. Checkout the [DeployHQ Guide](https://www.deployhq.com/guides/deploy-react-router-from-github) for more information.
|
|
@@ -37,6 +37,5 @@ npx create-react-router@latest --template remix-run/react-router-templates/<temp
|
|
|
37
37
|
|
|
38
38
|
Next: [Routing](./routing)
|
|
39
39
|
|
|
40
|
-
[manual_usage]: ../how-to/manual-usage
|
|
41
40
|
[default-template]: https://github.com/remix-run/react-router-templates/tree/main/default
|
|
42
41
|
[react-router-templates]: https://github.com/remix-run/react-router-templates
|
package/docs/start/modes.md
CHANGED
|
@@ -98,7 +98,6 @@ Every mode supports any architecture and deployment target, so the question isn'
|
|
|
98
98
|
- are considering Next.js, Solid Start, SvelteKit, Astro, TanStack Start, etc. and want to compare
|
|
99
99
|
- just want to build something with React
|
|
100
100
|
- might want to server render, might not
|
|
101
|
-
- are coming from Remix (React Router v7 is the "next version" after Remix v2)
|
|
102
101
|
- are migrating from Next.js
|
|
103
102
|
|
|
104
103
|
[→ Get Started with Framework Mode](./framework/installation).
|
|
@@ -113,7 +112,7 @@ Every mode supports any architecture and deployment target, so the question isn'
|
|
|
113
112
|
**Use Declarative Mode if you:**
|
|
114
113
|
|
|
115
114
|
- want to use React Router as simply as possible
|
|
116
|
-
- are coming from
|
|
115
|
+
- are coming from earlier React Router versions and are happy with the `<BrowserRouter>`
|
|
117
116
|
- have a data layer that either skips pending states (like local first, background data replication/sync) or has its own abstractions for them
|
|
118
117
|
- are coming from Create React App (you may want to consider framework mode though)
|
|
119
118
|
|
|
@@ -28,8 +28,8 @@ The initial setup requires the most work. However, once complete, you can adopt
|
|
|
28
28
|
|
|
29
29
|
To use the Vite plugin, your project requires:
|
|
30
30
|
|
|
31
|
-
- Node.js
|
|
32
|
-
- Vite
|
|
31
|
+
- Node.js 22.22.0+
|
|
32
|
+
- Vite 7+ or Vite 8+
|
|
33
33
|
|
|
34
34
|
## 1. Install the Vite plugin
|
|
35
35
|
|
package/docs/upgrading/future.md
CHANGED
|
@@ -1,31 +1,78 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Future
|
|
2
|
+
title: Future Changes
|
|
3
3
|
order: 1
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Future
|
|
6
|
+
# Future Changes
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
We try our best to keep major version upgrades simple and boring through the use of opt-in APIs and [Future Flags][api-development-strategy]. Future flags are used to gate breaking changes that don't otherwise have a good call-site opt-in strategy. By adopting all opt-in APIs and future flags, you should be able to upgrade to the next major version of React Router with minimal changes.
|
|
9
|
+
|
|
10
|
+
We plan to ship new major versions roughly once a year as described in our [Open Governance Model][governance], so this guide will continue to track future changes you can adopt ahead of the next major release. v9 is currently estimated for mid-2027 when Node 22 reaches EOL.
|
|
9
11
|
|
|
10
12
|
We highly recommend you make a commit after each step and ship it instead of doing everything all at once. Most flags can be adopted in any order, with exceptions noted below.
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
<docs-info>This is an evolving document that will be updated throughout the duration of v8</docs-info>
|
|
15
|
+
|
|
16
|
+
## Minimum Versions
|
|
17
|
+
|
|
18
|
+
[MODES: framework, data, declarative]
|
|
19
|
+
|
|
20
|
+
<br/>
|
|
21
|
+
<br/>
|
|
22
|
+
|
|
23
|
+
React Router v9 will require the following minimum versions (as of now). You can prepare for the upgrade by updating them while still on v8:
|
|
24
|
+
|
|
25
|
+
- `node@24+`
|
|
13
26
|
|
|
14
|
-
|
|
27
|
+
## Update to latest v8.x
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
Before adopting any future flags or call-site opt-in changes, you should update to the latest minor version of v8.x to make sure you have access to the latest flags. You may see a number of deprecation warnings as you upgrade, which we'll cover below.
|
|
30
|
+
|
|
31
|
+
👉 Update to latest v8
|
|
17
32
|
|
|
18
33
|
```sh
|
|
19
|
-
npm install react-router@
|
|
34
|
+
npm install react-router@8 @react-router/{dev,node,etc.}@8
|
|
20
35
|
```
|
|
21
36
|
|
|
37
|
+
## Future Flags
|
|
38
|
+
|
|
39
|
+
_No future flags yet_
|
|
40
|
+
|
|
41
|
+
## Other Planned Breaking Changes
|
|
42
|
+
|
|
43
|
+
_No known planned breaking changes yet_
|
|
44
|
+
|
|
22
45
|
## Unstable Future Flags (Optional)
|
|
23
46
|
|
|
24
|
-
We document some [unstable] flags here as a reference for folks contributing to the project via beta testing, but they are not generally recommended for production use and may
|
|
47
|
+
We document some [unstable] flags here as a reference for folks contributing to the project via beta testing, but they are not generally recommended for production use and may have breaking changes in patch or minor releases - adopt with caution!
|
|
48
|
+
|
|
49
|
+
### `future.unstable_optimizeDeps`
|
|
50
|
+
|
|
51
|
+
[MODES: framework]
|
|
52
|
+
|
|
53
|
+
<br/>
|
|
54
|
+
<br/>
|
|
55
|
+
|
|
56
|
+
**Background**
|
|
57
|
+
|
|
58
|
+
This flag lets React Router provide Vite's dependency optimizer with the client entry file and route module files. This can improve dependency optimization in development, but the behavior is still experimental.
|
|
59
|
+
|
|
60
|
+
👉 **Enable the Flag**
|
|
61
|
+
|
|
62
|
+
```ts filename=react-router.config.ts
|
|
63
|
+
import type { Config } from "@react-router/dev/config";
|
|
64
|
+
|
|
65
|
+
export default {
|
|
66
|
+
future: {
|
|
67
|
+
unstable_optimizeDeps: true,
|
|
68
|
+
},
|
|
69
|
+
} satisfies Config;
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Update your Code**
|
|
25
73
|
|
|
26
|
-
|
|
74
|
+
No code changes are required. If you run into dependency optimization issues after enabling this flag, remove the flag and restart the dev server.
|
|
27
75
|
|
|
28
76
|
[api-development-strategy]: ../community/api-development-strategy
|
|
77
|
+
[governance]: https://github.com/remix-run/react-router/blob/main/GOVERNANCE.md#design-goals
|
|
29
78
|
[unstable]: ../community/api-development-strategy#unstable-flags
|
|
30
|
-
[observability]: ../how-to/instrumentation
|
|
31
|
-
[vite-environment]: https://vite.dev/guide/api-environment
|
|
@@ -26,8 +26,8 @@ The initial setup requires the most work. However, once complete, you can adopt
|
|
|
26
26
|
|
|
27
27
|
To use the Vite plugin, your project requires:
|
|
28
28
|
|
|
29
|
-
- Node.js
|
|
30
|
-
- Vite
|
|
29
|
+
- Node.js 22.22.0+
|
|
30
|
+
- Vite 7+ or Vite 8+
|
|
31
31
|
|
|
32
32
|
## 1. Move route definitions into route modules
|
|
33
33
|
|
|
@@ -276,7 +276,10 @@ If your current `src/main.tsx` looks like this:
|
|
|
276
276
|
```tsx filename=src/main.tsx
|
|
277
277
|
import React from "react";
|
|
278
278
|
import ReactDOM from "react-dom/client";
|
|
279
|
-
import {
|
|
279
|
+
import {
|
|
280
|
+
createBrowserRouter,
|
|
281
|
+
RouterProvider,
|
|
282
|
+
} from "react-router";
|
|
280
283
|
import App from "./App";
|
|
281
284
|
|
|
282
285
|
const router = createBrowserRouter([
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Updating from v7
|
|
3
|
+
order: 2
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Upgrading from v7
|
|
7
|
+
|
|
8
|
+
We try our best to keep major version upgrades simple and boring through the use of opt-in APIs and [Future Flags][api-development-strategy]. Future flags are used to gate breaking changes that don't otherwise have a good call-site opt-in strategy. By adopting all opt-in APIs and future flags, you should be able to upgrade to the next major version of React Router with minimal changes.
|
|
9
|
+
|
|
10
|
+
We highly recommend you make a commit after each step and ship it instead of doing everything all at once. Most flags can be adopted in any order, with exceptions noted below.
|
|
11
|
+
|
|
12
|
+
## Minimum Versions
|
|
13
|
+
|
|
14
|
+
[MODES: framework, data, declarative]
|
|
15
|
+
|
|
16
|
+
<br/>
|
|
17
|
+
<br/>
|
|
18
|
+
|
|
19
|
+
React Router v8 requires the following minimum versions. You can prepare for the upgrade by updating them while still on v7:
|
|
20
|
+
|
|
21
|
+
- `node@22.22+`
|
|
22
|
+
- `react@19.2.7+`/`react-dom@19.2.7+`
|
|
23
|
+
|
|
24
|
+
Framework mode will also require:
|
|
25
|
+
|
|
26
|
+
- `vite@7+` (requires `future.v8_viteEnvironmentApi`)
|
|
27
|
+
- also make sure any custom Vite plugins or config are compatible with Vite 7
|
|
28
|
+
|
|
29
|
+
## Update to latest v7.x
|
|
30
|
+
|
|
31
|
+
Before adopting any future flags or call-site opt-in changes, you should update to the latest minor version of v7.x to make sure you have access to the latest flags. You may see a number of deprecation warnings as you upgrade, which we'll cover below.
|
|
32
|
+
|
|
33
|
+
👉 Update to latest v7
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
npm install react-router@7 @react-router/{dev,node,etc.}@7
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Future Flags
|
|
40
|
+
|
|
41
|
+
### `future.v8_middleware`
|
|
42
|
+
|
|
43
|
+
[MODES: framework, data]
|
|
44
|
+
|
|
45
|
+
<br/>
|
|
46
|
+
<br/>
|
|
47
|
+
|
|
48
|
+
**Background**
|
|
49
|
+
|
|
50
|
+
Middleware allows you to run code before and after the [`Response`][Response] generation for the matched path. This enables common patterns like authentication, logging, error handling, and data preprocessing in a reusable way. Please see the [docs](../how-to/middleware) for more information.
|
|
51
|
+
|
|
52
|
+
👉 **Enable the Flag**
|
|
53
|
+
|
|
54
|
+
In Framework mode:
|
|
55
|
+
|
|
56
|
+
```ts filename=react-router.config.ts
|
|
57
|
+
import type { Config } from "@react-router/dev/config";
|
|
58
|
+
|
|
59
|
+
export default {
|
|
60
|
+
future: {
|
|
61
|
+
v8_middleware: true,
|
|
62
|
+
},
|
|
63
|
+
} satisfies Config;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
In Data mode:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { createBrowserRouter } from "react-router";
|
|
70
|
+
|
|
71
|
+
const router = createBrowserRouter(routes, {
|
|
72
|
+
future: {
|
|
73
|
+
v8_middleware: true,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Update your Code**
|
|
79
|
+
|
|
80
|
+
If you're using the `context` parameter in `loader` and `action` functions, you may need to update your code:
|
|
81
|
+
|
|
82
|
+
- In Framework mode, if you're using `react-router-serve`, you should not need to make any updates. Otherwise, this only applies if you have a custom server with a `getLoadContext` function. Please see the docs on the middleware [`getLoadContext` changes](../how-to/middleware#changes-to-getloadcontextapploadcontext) and the instructions to [migrate to the new API](../how-to/middleware#migration-from-apploadcontext).
|
|
83
|
+
- In Data mode, add the `Future` module augmentation described in the [middleware docs](../how-to/middleware#1-typescript-augment-future-for-loaderaction-context) so `context` is typed correctly.
|
|
84
|
+
|
|
85
|
+
### `future.v8_splitRouteModules`
|
|
86
|
+
|
|
87
|
+
[MODES: framework]
|
|
88
|
+
|
|
89
|
+
<br/>
|
|
90
|
+
<br/>
|
|
91
|
+
|
|
92
|
+
**Background**
|
|
93
|
+
|
|
94
|
+
This feature enables splitting client-side route exports (`clientLoader`, `clientAction`, `clientMiddleware`, `HydrateFallback`) into separate chunks that can be loaded independently from the route component. This allows these exports to be fetched and executed while the component code is still downloading, improving performance for client-side data loading.
|
|
95
|
+
|
|
96
|
+
This can be set to `true` for opt-in behavior, or `"enforce"` to require all routes to be splittable (which will cause build failures for routes that cannot be split due to shared code).
|
|
97
|
+
|
|
98
|
+
👉 **Enable the Flag**
|
|
99
|
+
|
|
100
|
+
```ts filename=react-router.config.ts
|
|
101
|
+
import type { Config } from "@react-router/dev/config";
|
|
102
|
+
|
|
103
|
+
export default {
|
|
104
|
+
future: {
|
|
105
|
+
v8_splitRouteModules: true,
|
|
106
|
+
},
|
|
107
|
+
} satisfies Config;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Update your Code**
|
|
111
|
+
|
|
112
|
+
No code changes are required. This is an optimization feature that works automatically once enabled.
|
|
113
|
+
|
|
114
|
+
### `future.v8_viteEnvironmentApi`
|
|
115
|
+
|
|
116
|
+
[MODES: framework]
|
|
117
|
+
|
|
118
|
+
<br/>
|
|
119
|
+
<br/>
|
|
120
|
+
|
|
121
|
+
**Background**
|
|
122
|
+
|
|
123
|
+
This enables support for the experimental Vite Environment API, which provides a more flexible and powerful way to configure Vite environments. This is only available when using Vite 6+.
|
|
124
|
+
|
|
125
|
+
👉 **Enable the Flag**
|
|
126
|
+
|
|
127
|
+
```ts filename=react-router.config.ts
|
|
128
|
+
import type { Config } from "@react-router/dev/config";
|
|
129
|
+
|
|
130
|
+
export default {
|
|
131
|
+
future: {
|
|
132
|
+
v8_viteEnvironmentApi: true,
|
|
133
|
+
},
|
|
134
|
+
} satisfies Config;
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Update your Code**
|
|
138
|
+
|
|
139
|
+
Most users won't need to make any changes. However, if you have custom Vite configuration that previously relied on the `isSsrBuild` flag — such as a custom server build that sets `build.rollupOptions.input` — you'll need to move that configuration under the per-environment [Environment API][vite-environment] config instead.
|
|
140
|
+
|
|
141
|
+
For example, a custom server build should move its SSR `rollupOptions` from the top-level `build` config into `environments.ssr.build`:
|
|
142
|
+
|
|
143
|
+
```diff filename=vite.config.ts
|
|
144
|
+
import { reactRouter } from "@react-router/dev/vite";
|
|
145
|
+
import { defineConfig } from "vite";
|
|
146
|
+
|
|
147
|
+
-export default defineConfig(({ isSsrBuild }) => ({
|
|
148
|
+
- build: {
|
|
149
|
+
- rollupOptions: isSsrBuild
|
|
150
|
+
- ? {
|
|
151
|
+
- input: "./server/app.ts",
|
|
152
|
+
- }
|
|
153
|
+
- : undefined,
|
|
154
|
+
- },
|
|
155
|
+
+export default defineConfig({
|
|
156
|
+
+ environments: {
|
|
157
|
+
+ ssr: {
|
|
158
|
+
+ build: {
|
|
159
|
+
+ rollupOptions: {
|
|
160
|
+
+ input: "./server/app.ts",
|
|
161
|
+
+ },
|
|
162
|
+
+ },
|
|
163
|
+
+ },
|
|
164
|
+
+ },
|
|
165
|
+
plugins: [reactRouter()],
|
|
166
|
+
-}));
|
|
167
|
+
+});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
See the [`node-custom-server` template][node-custom-server-template] for a complete example.
|
|
171
|
+
|
|
172
|
+
### `future.v8_passThroughRequests`
|
|
173
|
+
|
|
174
|
+
[MODES: framework]
|
|
175
|
+
|
|
176
|
+
<br/>
|
|
177
|
+
<br/>
|
|
178
|
+
|
|
179
|
+
**Background**
|
|
180
|
+
|
|
181
|
+
By default, React Router normalizes the `request.url` passed to your `loader`, `action`, and `middleware` functions by removing React Router's internal implementation details. Specifically, it removes `.data` suffixes and internal search parameters like `?index` and `?_routes`.
|
|
182
|
+
|
|
183
|
+
This flag eliminates that normalization and passes the raw HTTP `request` instance to your handlers. This provides a few benefits:
|
|
184
|
+
|
|
185
|
+
- Reduces server-side overhead by eliminating multiple `new Request()` calls on the critical path
|
|
186
|
+
- Allows you to distinguish document from data requests in your handlers based on the presence of a `.data` suffix (useful for [observability] purposes)
|
|
187
|
+
|
|
188
|
+
If you were previously relying on the normalization of `request.url`, you can switch to use the new sibling `url` parameter which contains a `URL` instance representing the normalized location.
|
|
189
|
+
|
|
190
|
+
👉 **Enable the Flag**
|
|
191
|
+
|
|
192
|
+
```ts filename=react-router.config.ts
|
|
193
|
+
import type { Config } from "@react-router/dev/config";
|
|
194
|
+
|
|
195
|
+
export default {
|
|
196
|
+
future: {
|
|
197
|
+
v8_passThroughRequests: true,
|
|
198
|
+
},
|
|
199
|
+
} satisfies Config;
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Update your Code**
|
|
203
|
+
|
|
204
|
+
If your code relies on inspecting the request URL, you should review it for any assumptions about the URL format:
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
// ❌ Before: assuming no `.data` suffix in `request.url` pathname
|
|
208
|
+
export async function loader({
|
|
209
|
+
request,
|
|
210
|
+
}: Route.LoaderArgs) {
|
|
211
|
+
let url = new URL(request.url);
|
|
212
|
+
if (url.pathname === "/path") {
|
|
213
|
+
// This check might now behave differently because the request pathname will
|
|
214
|
+
// contain the `.data` suffix on data requests
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ✅ After: use `url` for normalized routing logic and `request.url`
|
|
219
|
+
// for raw routing logic
|
|
220
|
+
export async function loader({
|
|
221
|
+
request,
|
|
222
|
+
url,
|
|
223
|
+
}: Route.LoaderArgs) {
|
|
224
|
+
if (url.pathname === "/path") {
|
|
225
|
+
// This will always have the `.data` suffix stripped
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// And now you can distinguish between document versus data requests
|
|
229
|
+
let isDataRequest = new URL(
|
|
230
|
+
request.url,
|
|
231
|
+
).pathname.endsWith(".data");
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### `future.v8_trailingSlashAwareDataRequests`
|
|
236
|
+
|
|
237
|
+
[MODES: framework]
|
|
238
|
+
|
|
239
|
+
<br/>
|
|
240
|
+
<br/>
|
|
241
|
+
|
|
242
|
+
**Background**
|
|
243
|
+
|
|
244
|
+
React Router serves Framework mode data requests from `.data` URLs. Previously, data requests for routes with and without trailing slashes could map to the same `.data` URL because trailing slashes were not considered during URL generation. This flag preserves trailing slash semantics for data request URLs to avoid ambiguity when your app distinguishes between trailing-slash and non-trailing-slash URLs.
|
|
245
|
+
|
|
246
|
+
Currently, your HTTP and `request` pathnames would be as follows for `/a/b/c` and `/a/b/c/`
|
|
247
|
+
|
|
248
|
+
| URL `/a/b/c` | **HTTP pathname** | **`request` pathname`** |
|
|
249
|
+
| ------------ | ----------------- | ----------------------- |
|
|
250
|
+
| **Document** | `/a/b/c` | `/a/b/c` ✅ |
|
|
251
|
+
| **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
|
|
252
|
+
|
|
253
|
+
| URL `/a/b/c/` | **HTTP pathname** | **`request` pathname`** |
|
|
254
|
+
| ------------- | ----------------- | ----------------------- |
|
|
255
|
+
| **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
|
|
256
|
+
| **Data** | `/a/b/c.data` | `/a/b/c` ⚠️ |
|
|
257
|
+
|
|
258
|
+
With this flag enabled, these pathnames will be made consistent though a new `_.data` format for client-side `.data` requests:
|
|
259
|
+
|
|
260
|
+
| URL `/a/b/c` | **HTTP pathname** | **`request` pathname`** |
|
|
261
|
+
| ------------ | ----------------- | ----------------------- |
|
|
262
|
+
| **Document** | `/a/b/c` | `/a/b/c` ✅ |
|
|
263
|
+
| **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
|
|
264
|
+
|
|
265
|
+
| URL `/a/b/c/` | **HTTP pathname** | **`request` pathname`** |
|
|
266
|
+
| ------------- | ------------------ | ----------------------- |
|
|
267
|
+
| **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
|
|
268
|
+
| **Data** | `/a/b/c/_.data` ⬅️ | `/a/b/c/` ✅ |
|
|
269
|
+
|
|
270
|
+
This flag also aligns the root data request to match this behavior by changing it from `/_root.data` to `/_.data`.
|
|
271
|
+
|
|
272
|
+
👉 **Enable the Flag**
|
|
273
|
+
|
|
274
|
+
```ts filename=react-router.config.ts
|
|
275
|
+
import type { Config } from "@react-router/dev/config";
|
|
276
|
+
|
|
277
|
+
export default {
|
|
278
|
+
future: {
|
|
279
|
+
v8_trailingSlashAwareDataRequests: true,
|
|
280
|
+
},
|
|
281
|
+
} satisfies Config;
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Update your Code**
|
|
285
|
+
|
|
286
|
+
If you have custom app, CDN, cache, or rewrite logic that matches `.data` request URLs, update it to handle the new trailing-slash-aware `/_.data` format.
|
|
287
|
+
|
|
288
|
+
## Other Planned Breaking Changes
|
|
289
|
+
|
|
290
|
+
The changes in this section are not controlled by future flags, but you can update your code in v7 to be ready for v8.
|
|
291
|
+
|
|
292
|
+
### `meta` `data` Argument
|
|
293
|
+
|
|
294
|
+
[MODES: framework]
|
|
295
|
+
|
|
296
|
+
<br/>
|
|
297
|
+
<br/>
|
|
298
|
+
|
|
299
|
+
**Background**
|
|
300
|
+
|
|
301
|
+
The `data` fields passed to route module `meta` functions are deprecated and will be removed in React Router v8. Use `loaderData` instead on `MetaArgs` and each item in `MetaArgs.matches`.
|
|
302
|
+
|
|
303
|
+
👉 **Update your Code**
|
|
304
|
+
|
|
305
|
+
Replace `data` with `loaderData` in your `meta` functions:
|
|
306
|
+
|
|
307
|
+
```diff
|
|
308
|
+
export function meta({
|
|
309
|
+
- data,
|
|
310
|
+
+ loaderData,
|
|
311
|
+
matches,
|
|
312
|
+
}: Route.MetaArgs) {
|
|
313
|
+
return [
|
|
314
|
+
{
|
|
315
|
+
- title: data.title,
|
|
316
|
+
+ title: loaderData.title,
|
|
317
|
+
},
|
|
318
|
+
];
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
If you read data from parent matches, update those references too:
|
|
323
|
+
|
|
324
|
+
```diff
|
|
325
|
+
export function meta({ matches }: Route.MetaArgs) {
|
|
326
|
+
let rootMatch = matches.find((match) => match.id === "root");
|
|
327
|
+
- let rootData = rootMatch?.data;
|
|
328
|
+
+ let rootData = rootMatch?.loaderData;
|
|
329
|
+
|
|
330
|
+
return [{ title: rootData?.siteTitle }];
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### `react-router-dom`
|
|
335
|
+
|
|
336
|
+
[MODES: framework, data, declarative]
|
|
337
|
+
|
|
338
|
+
<br/>
|
|
339
|
+
<br/>
|
|
340
|
+
|
|
341
|
+
**Background**
|
|
342
|
+
|
|
343
|
+
React Router v8 will remove the `react-router-dom` re-export package. In v8, you should import DOM-specific APIs from `react-router/dom` and everything else from `react-router`.
|
|
344
|
+
|
|
345
|
+
👉 **Update your Code**
|
|
346
|
+
|
|
347
|
+
Uninstall `react-router-dom`:
|
|
348
|
+
|
|
349
|
+
```sh
|
|
350
|
+
npm uninstall react-router-dom
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Replace `react-router-dom` imports with `react-router` imports:
|
|
354
|
+
|
|
355
|
+
```diff
|
|
356
|
+
-import { Link, useLocation } from "react-router-dom";
|
|
357
|
+
+import { Link, useLocation } from "react-router";
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
For DOM-specific APIs, import from `react-router/dom`:
|
|
361
|
+
|
|
362
|
+
```diff
|
|
363
|
+
-import { RouterProvider } from "react-router-dom";
|
|
364
|
+
+import { RouterProvider } from "react-router/dom";
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Cloudflare Vite Plugin
|
|
368
|
+
|
|
369
|
+
[MODES: framework]
|
|
370
|
+
|
|
371
|
+
<br/>
|
|
372
|
+
<br/>
|
|
373
|
+
|
|
374
|
+
**Background**
|
|
375
|
+
|
|
376
|
+
React Router v8 will remove the React Router Cloudflare dev proxy. Cloudflare projects should use [`@cloudflare/vite-plugin`][cloudflare-vite-plugin] instead.
|
|
377
|
+
|
|
378
|
+
👉 **Update your Code**
|
|
379
|
+
|
|
380
|
+
Replace `cloudflareDevProxy` with `cloudflare`:
|
|
381
|
+
|
|
382
|
+
```diff filename=vite.config.ts
|
|
383
|
+
import { reactRouter } from "@react-router/dev/vite";
|
|
384
|
+
-import { cloudflareDevProxy } from "@react-router/dev/vite/cloudflare";
|
|
385
|
+
+import { cloudflare } from "@cloudflare/vite-plugin";
|
|
386
|
+
import { defineConfig } from "vite";
|
|
387
|
+
|
|
388
|
+
export default defineConfig({
|
|
389
|
+
plugins: [
|
|
390
|
+
- cloudflareDevProxy(),
|
|
391
|
+
+ cloudflare(),
|
|
392
|
+
reactRouter(),
|
|
393
|
+
],
|
|
394
|
+
});
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### `@react-router/architect` `useRequestContextDomainName`
|
|
398
|
+
|
|
399
|
+
[MODES: framework]
|
|
400
|
+
|
|
401
|
+
<br/>
|
|
402
|
+
<br/>
|
|
403
|
+
|
|
404
|
+
**Background**
|
|
405
|
+
|
|
406
|
+
The `@react-router/architect` adapter currently uses `X-Forwarded-Host` when creating the `request`, falling back to the `Host` header. In React Router v8, the adapter will use `event.requestContext.domainName` by default, falling back to the `Host` header.
|
|
407
|
+
|
|
408
|
+
👉 **Update your Code**
|
|
409
|
+
|
|
410
|
+
Opt in to the v8 behavior now by passing `useRequestContextDomainName: true`:
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
import { createRequestHandler } from "@react-router/architect";
|
|
414
|
+
import * as build from "./build/server";
|
|
415
|
+
|
|
416
|
+
export const handler = createRequestHandler({
|
|
417
|
+
build,
|
|
418
|
+
useRequestContextDomainName: true,
|
|
419
|
+
});
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
This option will be removed in v8 once the `event.requestContext.domainName` behavior is the default.
|
|
423
|
+
|
|
424
|
+
## Upgrade to v8
|
|
425
|
+
|
|
426
|
+
Now that your app is caught up, you can simply update to v8 (theoretically!) without issue.
|
|
427
|
+
|
|
428
|
+
```shellscript nonumber
|
|
429
|
+
# data/declarative mode
|
|
430
|
+
npm install react-router@latest
|
|
431
|
+
|
|
432
|
+
# framework mode
|
|
433
|
+
npm install react-router@latest @react-router/{dev,node,etc.}@latest
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Congratulations, you're now on v8!
|
|
437
|
+
|
|
438
|
+
[api-development-strategy]: ../community/api-development-strategy
|
|
439
|
+
[observability]: ../how-to/instrumentation
|
|
440
|
+
[Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response
|
|
441
|
+
[vite-environment]: https://vite.dev/guide/api-environment
|
|
442
|
+
[node-custom-server-template]: https://github.com/remix-run/react-router-templates/blob/7c617a435510bc3add3a5395c07bc65328b65e9e/node-custom-server/vite.config.ts
|
|
443
|
+
[cloudflare-vite-plugin]: https://developers.cloudflare.com/workers/vite-plugin/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-router",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "8.0.0
|
|
4
|
+
"version": "8.0.0",
|
|
5
5
|
"description": "Declarative routing for React",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"react",
|
|
@@ -85,17 +85,17 @@
|
|
|
85
85
|
"@types/node": "^22.19.19",
|
|
86
86
|
"jest-environment-jsdom": "^30.4.1",
|
|
87
87
|
"premove": "^4.0.0",
|
|
88
|
-
"react": "^19.2.
|
|
89
|
-
"react-dom": "^19.2.
|
|
90
|
-
"react-test-renderer": "^19.2.
|
|
88
|
+
"react": "^19.2.7",
|
|
89
|
+
"react-dom": "^19.2.7",
|
|
90
|
+
"react-test-renderer": "^19.2.7",
|
|
91
91
|
"tsdown": "^0.22.0",
|
|
92
92
|
"typescript": "^6.0.3",
|
|
93
93
|
"undici": "^6.19.2",
|
|
94
94
|
"wireit": "0.14.12"
|
|
95
95
|
},
|
|
96
96
|
"peerDependencies": {
|
|
97
|
-
"react": ">=19.2.
|
|
98
|
-
"react-dom": ">=19.2.
|
|
97
|
+
"react": ">=19.2.7",
|
|
98
|
+
"react-dom": ">=19.2.7"
|
|
99
99
|
},
|
|
100
100
|
"peerDependenciesMeta": {
|
|
101
101
|
"react-dom": {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"README.md"
|
|
111
111
|
],
|
|
112
112
|
"engines": {
|
|
113
|
-
"node": ">=22.
|
|
113
|
+
"node": ">=22.22.0"
|
|
114
114
|
},
|
|
115
115
|
"scripts": {
|
|
116
116
|
"build": "wireit",
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* react-router v8.0.0-pre.0
|
|
3
|
-
*
|
|
4
|
-
* Copyright (c) Remix Software Inc.
|
|
5
|
-
*
|
|
6
|
-
* This source code is licensed under the MIT license found in the
|
|
7
|
-
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
-
*
|
|
9
|
-
* @license MIT
|
|
10
|
-
*/
|
|
11
|
-
import { ErrorResponseImpl } from "../../router/utils.js";
|
|
12
|
-
//#region lib/dom/ssr/errors.ts
|
|
13
|
-
function deserializeErrors(errors) {
|
|
14
|
-
if (!errors) return null;
|
|
15
|
-
let entries = Object.entries(errors);
|
|
16
|
-
let serialized = {};
|
|
17
|
-
for (let [key, val] of entries) if (val && val.__type === "RouteErrorResponse") serialized[key] = new ErrorResponseImpl(val.status, val.statusText, val.data, val.internal === true);
|
|
18
|
-
else if (val && val.__type === "Error") {
|
|
19
|
-
if (val.__subType) {
|
|
20
|
-
let ErrorConstructor = window[val.__subType];
|
|
21
|
-
if (typeof ErrorConstructor === "function") try {
|
|
22
|
-
let error = new ErrorConstructor(val.message);
|
|
23
|
-
error.stack = val.stack;
|
|
24
|
-
serialized[key] = error;
|
|
25
|
-
} catch (e) {}
|
|
26
|
-
}
|
|
27
|
-
if (serialized[key] == null) {
|
|
28
|
-
let error = new Error(val.message);
|
|
29
|
-
error.stack = val.stack;
|
|
30
|
-
serialized[key] = error;
|
|
31
|
-
}
|
|
32
|
-
} else serialized[key] = val;
|
|
33
|
-
return serialized;
|
|
34
|
-
}
|
|
35
|
-
//#endregion
|
|
36
|
-
export { deserializeErrors };
|