react-router 7.2.0-pre.6 → 7.3.0-pre.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +268 -28
- package/dist/development/{chunk-TEULL7XU.mjs → chunk-W5LWFPOT.mjs} +851 -336
- package/dist/development/dom-export.d.mts +13 -3
- package/dist/development/dom-export.d.ts +13 -3
- package/dist/development/dom-export.js +371 -79
- package/dist/development/dom-export.mjs +14 -5
- package/dist/development/{fog-of-war-Cm1iXIp7.d.ts → fog-of-war-CvttGpNz.d.ts} +93 -9
- package/dist/{production/fog-of-war-Cm1iXIp7.d.ts → development/fog-of-war-Da8gpnoZ.d.mts} +93 -9
- package/dist/{production/data-CQbyyGzl.d.mts → development/future-ldDp5FKH.d.mts} +11 -1
- package/dist/development/{data-CQbyyGzl.d.mts → future-ldDp5FKH.d.ts} +11 -1
- package/dist/development/index.d.mts +16 -14
- package/dist/development/index.d.ts +16 -14
- package/dist/development/index.js +853 -336
- package/dist/development/index.mjs +6 -2
- package/dist/development/lib/types/route-module.d.mts +24 -6
- package/dist/development/lib/types/route-module.d.ts +24 -6
- package/dist/development/lib/types/route-module.js +1 -1
- package/dist/development/lib/types/route-module.mjs +1 -1
- package/dist/{production/route-data-BmvbmBej.d.mts → development/route-data-H2S3hwhf.d.mts} +66 -13
- package/dist/development/{route-data-BmvbmBej.d.mts → route-data-H2S3hwhf.d.ts} +66 -13
- package/dist/production/{chunk-ZQLTZ2R5.mjs → chunk-ZITGHOQF.mjs} +851 -336
- package/dist/production/dom-export.d.mts +13 -3
- package/dist/production/dom-export.d.ts +13 -3
- package/dist/production/dom-export.js +371 -79
- package/dist/production/dom-export.mjs +14 -5
- package/dist/production/{fog-of-war-BALYJxf_.d.mts → fog-of-war-CvttGpNz.d.ts} +93 -9
- package/dist/{development/fog-of-war-BALYJxf_.d.mts → production/fog-of-war-Da8gpnoZ.d.mts} +93 -9
- package/dist/{development/data-CQbyyGzl.d.ts → production/future-ldDp5FKH.d.mts} +11 -1
- package/dist/production/{data-CQbyyGzl.d.ts → future-ldDp5FKH.d.ts} +11 -1
- package/dist/production/index.d.mts +16 -14
- package/dist/production/index.d.ts +16 -14
- package/dist/production/index.js +853 -336
- package/dist/production/index.mjs +6 -2
- package/dist/production/lib/types/route-module.d.mts +24 -6
- package/dist/production/lib/types/route-module.d.ts +24 -6
- package/dist/production/lib/types/route-module.js +1 -1
- package/dist/production/lib/types/route-module.mjs +1 -1
- package/dist/{development/route-data-BmvbmBej.d.ts → production/route-data-H2S3hwhf.d.mts} +66 -13
- package/dist/production/{route-data-BmvbmBej.d.ts → route-data-H2S3hwhf.d.ts} +66 -13
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,45 +1,265 @@
|
|
|
1
1
|
# `react-router`
|
|
2
2
|
|
|
3
|
-
## 7.
|
|
3
|
+
## 7.3.0-pre.0
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Add `fetcherKey` as a parameter to `patchRoutesOnNavigation` ([#13061](https://github.com/remix-run/react-router/pull/13061))
|
|
8
|
+
|
|
9
|
+
- In framework mode, Lazy Route Discovery will now detect manifest version mismatches after a new deploy
|
|
10
|
+
- On navigations to undiscovered routes, this mismatch will trigger a document reload of the destination path
|
|
11
|
+
- On `fetcher` calls to undiscovered routes, this mismatch will trigger a document reload of the current path
|
|
6
12
|
|
|
7
13
|
### Patch Changes
|
|
8
14
|
|
|
9
|
-
-
|
|
15
|
+
- Skip resource route flow in dev server in SPA mode ([#13113](https://github.com/remix-run/react-router/pull/13113))
|
|
16
|
+
- Support middleware on routes (unstable) ([#12941](https://github.com/remix-run/react-router/pull/12941))
|
|
10
17
|
|
|
11
|
-
|
|
18
|
+
Middleware is implemented behind a `future.unstable_middleware` flag. To enable, you must enable the flag and the types in your `react-router-config.ts` file:
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
```ts
|
|
21
|
+
import type { Config } from "@react-router/dev/config";
|
|
22
|
+
import type { Future } from "react-router";
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
declare module "react-router" {
|
|
25
|
+
interface Future {
|
|
26
|
+
unstable_middleware: true; // 👈 Enable middleware types
|
|
27
|
+
}
|
|
28
|
+
}
|
|
16
29
|
|
|
17
|
-
|
|
30
|
+
export default {
|
|
31
|
+
future: {
|
|
32
|
+
unstable_middleware: true, // 👈 Enable middleware
|
|
33
|
+
},
|
|
34
|
+
} satisfies Config;
|
|
35
|
+
```
|
|
18
36
|
|
|
19
|
-
|
|
37
|
+
⚠️ Middleware is unstable and should not be adopted in production. There is at least one known de-optimization in route module loading for `clientMiddleware` that we will be addressing this before a stable release.
|
|
20
38
|
|
|
21
|
-
|
|
39
|
+
⚠️ Enabling middleware contains a breaking change to the `context` parameter passed to your `loader`/`action` functions - see below for more information.
|
|
22
40
|
|
|
23
|
-
|
|
41
|
+
Once enabled, routes can define an array of middleware functions that will run sequentially before route handlers run. These functions accept the same parameters as `loader`/`action` plus an additional `next` parameter to run the remaining data pipeline. This allows middlewares to perform logic before and after handlers execute.
|
|
24
42
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
43
|
+
```tsx
|
|
44
|
+
// Framework mode
|
|
45
|
+
export const unstable_middleware = [serverLogger, serverAuth]; // server
|
|
46
|
+
export const unstable_clientMiddleware = [clientLogger]; // client
|
|
47
|
+
|
|
48
|
+
// Library mode
|
|
49
|
+
const routes = [
|
|
50
|
+
{
|
|
51
|
+
path: "/",
|
|
52
|
+
// Middlewares are client-side for library mode SPA's
|
|
53
|
+
unstable_middleware: [clientLogger, clientAuth],
|
|
54
|
+
loader: rootLoader,
|
|
55
|
+
Component: Root,
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
```
|
|
32
59
|
|
|
33
|
-
|
|
60
|
+
Here's a simple example of a client-side logging middleware that can be placed on the root route:
|
|
34
61
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
62
|
+
```tsx
|
|
63
|
+
const clientLogger: Route.unstable_ClientMiddlewareFunction = async (
|
|
64
|
+
{ request },
|
|
65
|
+
next
|
|
66
|
+
) => {
|
|
67
|
+
let start = performance.now();
|
|
68
|
+
|
|
69
|
+
// Run the remaining middlewares and all route loaders
|
|
70
|
+
await next();
|
|
71
|
+
|
|
72
|
+
let duration = performance.now() - start;
|
|
73
|
+
console.log(`Navigated to ${request.url} (${duration}ms)`);
|
|
74
|
+
};
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Note that in the above example, the `next`/`middleware` functions don't return anything. This is by design as on the client there is no "response" to send over the network like there would be for middlewares running on the server. The data is all handled behind the scenes by the stateful `router`.
|
|
78
|
+
|
|
79
|
+
For a server-side middleware, the `next` function will return the HTTP `Response` that React Router will be sending across the wire, thus giving you a chance to make changes as needed. You may throw a new response to short circuit and respond immediately, or you may return a new or altered response to override the default returned by `next()`.
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
const serverLogger: Route.unstable_MiddlewareFunction = async (
|
|
83
|
+
{ request, params, context },
|
|
84
|
+
next
|
|
85
|
+
) => {
|
|
86
|
+
let start = performance.now();
|
|
87
|
+
|
|
88
|
+
// 👇 Grab the response here
|
|
89
|
+
let res = await next();
|
|
90
|
+
|
|
91
|
+
let duration = performance.now() - start;
|
|
92
|
+
console.log(`Navigated to ${request.url} (${duration}ms)`);
|
|
93
|
+
|
|
94
|
+
// 👇 And return it here (optional if you don't modify the response)
|
|
95
|
+
return res;
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
You can throw a `redirect` from a middleware to short circuit any remaining processing:
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { sessionContext } from "../context";
|
|
103
|
+
const serverAuth: Route.unstable_MiddlewareFunction = (
|
|
104
|
+
{ request, params, context },
|
|
105
|
+
next
|
|
106
|
+
) => {
|
|
107
|
+
let session = context.get(sessionContext);
|
|
108
|
+
let user = session.get("user");
|
|
109
|
+
if (!user) {
|
|
110
|
+
session.set("returnTo", request.url);
|
|
111
|
+
throw redirect("/login", 302);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
```
|
|
41
115
|
|
|
42
|
-
|
|
116
|
+
_Note that in cases like this where you don't need to do any post-processing you don't need to call the `next` function or return a `Response`._
|
|
117
|
+
|
|
118
|
+
Here's another example of using a server middleware to detect 404s and check the CMS for a redirect:
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
const redirects: Route.unstable_MiddlewareFunction = async ({
|
|
122
|
+
request,
|
|
123
|
+
next,
|
|
124
|
+
}) => {
|
|
125
|
+
// attempt to handle the request
|
|
126
|
+
let res = await next();
|
|
127
|
+
|
|
128
|
+
// if it's a 404, check the CMS for a redirect, do it last
|
|
129
|
+
// because it's expensive
|
|
130
|
+
if (res.status === 404) {
|
|
131
|
+
let cmsRedirect = await checkCMSRedirects(request.url);
|
|
132
|
+
if (cmsRedirect) {
|
|
133
|
+
throw redirect(cmsRedirect, 302);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return res;
|
|
138
|
+
};
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**`context` parameter**
|
|
142
|
+
|
|
143
|
+
When middleware is enabled, your application will use a different type of `context` parameter in your loaders and actions to provide better type safety. Instead of `AppLoadContext`, `context` will now be an instance of `ContextProvider` that you can use with type-safe contexts (similar to `React.createContext`):
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { unstable_createContext } from "react-router";
|
|
147
|
+
import { Route } from "./+types/root";
|
|
148
|
+
import type { Session } from "./sessions.server";
|
|
149
|
+
import { getSession } from "./sessions.server";
|
|
150
|
+
|
|
151
|
+
let sessionContext = unstable_createContext<Session>();
|
|
152
|
+
|
|
153
|
+
const sessionMiddleware: Route.unstable_MiddlewareFunction = ({
|
|
154
|
+
context,
|
|
155
|
+
request,
|
|
156
|
+
}) => {
|
|
157
|
+
let session = await getSession(request);
|
|
158
|
+
context.set(sessionContext, session);
|
|
159
|
+
// ^ must be of type Session
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// ... then in some downstream middleware
|
|
163
|
+
const loggerMiddleware: Route.unstable_MiddlewareFunction = ({
|
|
164
|
+
context,
|
|
165
|
+
request,
|
|
166
|
+
}) => {
|
|
167
|
+
let session = context.get(sessionContext);
|
|
168
|
+
// ^ typeof Session
|
|
169
|
+
console.log(session.get("userId"), request.method, request.url);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// ... or some downstream loader
|
|
173
|
+
export function loader({ context }: Route.LoaderArgs) {
|
|
174
|
+
let session = context.get(sessionContext);
|
|
175
|
+
let profile = await getProfile(session.get("userId"));
|
|
176
|
+
return { profile };
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
If you are using a custom server with a `getLoadContext` function, the return value for initial context values passed from the server adapter layer is no longer an object and should now return an `unstable_InitialContext` (`Map<RouterContext, unknown>`):
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
let adapterContext = unstable_createContext<MyAdapterContext>();
|
|
184
|
+
|
|
185
|
+
function getLoadContext(req, res): unstable_InitialContext {
|
|
186
|
+
let map = new Map();
|
|
187
|
+
map.set(adapterContext, getAdapterContext(req));
|
|
188
|
+
return map;
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
- Fix types for loaderData and actionData that contained `Record`s ([#13139](https://github.com/remix-run/react-router/pull/13139))
|
|
193
|
+
|
|
194
|
+
UNSTABLE(BREAKING):
|
|
195
|
+
|
|
196
|
+
`unstable_SerializesTo` added a way to register custom serialization types in Single Fetch for other library and framework authors like Apollo.
|
|
197
|
+
It was implemented with branded type whose branded property that was made optional so that casting arbitrary values was easy:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
// without the brand being marked as optional
|
|
201
|
+
let x1 = 42 as unknown as unstable_SerializesTo<number>;
|
|
202
|
+
// ^^^^^^^^^^
|
|
203
|
+
|
|
204
|
+
// with the brand being marked as optional
|
|
205
|
+
let x2 = 42 as unstable_SerializesTo<number>;
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
However, this broke type inference in `loaderData` and `actionData` for any `Record` types as those would now (incorrectly) match `unstable_SerializesTo`.
|
|
209
|
+
This affected all users, not just those that depended on `unstable_SerializesTo`.
|
|
210
|
+
To fix this, the branded property of `unstable_SerializesTo` is marked as required instead of optional.
|
|
211
|
+
|
|
212
|
+
For library and framework authors using `unstable_SerializesTo`, you may need to add `as unknown` casts before casting to `unstable_SerializesTo`.
|
|
213
|
+
|
|
214
|
+
- Fix single fetch `_root.data` requests when a `basename` is used ([#12898](https://github.com/remix-run/react-router/pull/12898))
|
|
215
|
+
- Add `context` support to client side data routers (unstable) ([#12941](https://github.com/remix-run/react-router/pull/12941))
|
|
216
|
+
|
|
217
|
+
Your application `loader` and `action` functions on the client will now receive a `context` parameter. This is an instance of `unstable_RouterContextProvider` that you use with type-safe contexts (similar to `React.createContext`) and is most useful with the corresponding `middleware`/`clientMiddleware` API's:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
import { unstable_createContext } from "react-router";
|
|
221
|
+
|
|
222
|
+
type User = {
|
|
223
|
+
/*...*/
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
let userContext = unstable_createContext<User>();
|
|
227
|
+
|
|
228
|
+
function sessionMiddleware({ context }) {
|
|
229
|
+
let user = await getUser();
|
|
230
|
+
context.set(userContext, user);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ... then in some downstream loader
|
|
234
|
+
function loader({ context }) {
|
|
235
|
+
let user = context.get(userContext);
|
|
236
|
+
let profile = await getProfile(user.id);
|
|
237
|
+
return { profile };
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Similar to server-side requests, a fresh `context` will be created per navigation (or `fetcher` call). If you have initial data you'd like to populate in the context for every request, you can provide an `unstable_getContext` function at the root of your app:
|
|
242
|
+
|
|
243
|
+
- Library mode - `createBrowserRouter(routes, { unstable_getContext })`
|
|
244
|
+
- Framework mode - `<HydratedRouter unstable_getContext>`
|
|
245
|
+
|
|
246
|
+
This function should return an value of type `unstable_InitialContext` which is a `Map<unstable_RouterContext, unknown>` of context's and initial values:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
const loggerContext = unstable_createContext<(...args: unknown[]) => void>();
|
|
250
|
+
|
|
251
|
+
function logger(...args: unknown[]) {
|
|
252
|
+
console.log(new Date.toISOString(), ...args);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function unstable_getContext() {
|
|
256
|
+
let map = new Map();
|
|
257
|
+
map.set(loggerContext, logger);
|
|
258
|
+
return map;
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## 7.2.0
|
|
43
263
|
|
|
44
264
|
### Minor Changes
|
|
45
265
|
|
|
@@ -73,12 +293,31 @@
|
|
|
73
293
|
To be consistent with runtime behavior, the generated types now correctly model the "last one wins" semantics of path parameters.
|
|
74
294
|
So `/a/1/b/2/c/3` now generates a type like `{ id: 3 }`.
|
|
75
295
|
|
|
76
|
-
|
|
296
|
+
- Don't apply Single Fetch revalidation de-optimization when in SPA mode since there is no server HTTP request ([#12948](https://github.com/remix-run/react-router/pull/12948))
|
|
77
297
|
|
|
78
|
-
|
|
298
|
+
- Properly handle revalidations to across a prerender/SPA boundary ([#13021](https://github.com/remix-run/react-router/pull/13021))
|
|
299
|
+
|
|
300
|
+
- In "hybrid" applications where some routes are pre-rendered and some are served from a SPA fallback, we need to avoid making `.data` requests if the path wasn't pre-rendered because the request will 404
|
|
301
|
+
- We don't know all the pre-rendered paths client-side, however:
|
|
302
|
+
- All `loader` data in `ssr:false` mode is static because it's generated at build time
|
|
303
|
+
- A route must use a `clientLoader` to do anything dynamic
|
|
304
|
+
- Therefore, if a route only has a `loader` and not a `clientLoader`, we disable revalidation by default because there is no new data to retrieve
|
|
305
|
+
- We short circuit and skip single fetch `.data` request logic if there are no server loaders with `shouldLoad=true` in our single fetch `dataStrategy`
|
|
306
|
+
- This ensures that the route doesn't cause a `.data` request that would 404 after a submission
|
|
307
|
+
|
|
308
|
+
- Error at build time in `ssr:false` + `prerender` apps for the edge case scenario of: ([#13021](https://github.com/remix-run/react-router/pull/13021))
|
|
309
|
+
|
|
310
|
+
- A parent route has only a `loader` (does not have a `clientLoader`)
|
|
311
|
+
- The parent route is pre-rendered
|
|
312
|
+
- The parent route has children routes which are not prerendered
|
|
313
|
+
- This means that when the child paths are loaded via the SPA fallback, the parent won't have any `loaderData` because there is no server on which to run the `loader`
|
|
314
|
+
- This can be resolved by either adding a parent `clientLoader` or pre-rendering the child paths
|
|
315
|
+
- If you add a `clientLoader`, calling the `serverLoader()` on non-prerendered paths will throw a 404
|
|
79
316
|
|
|
80
|
-
- Don't apply Single Fetch revalidation de-optimization when in SPA mode since there is no server HTTP request ([#12948](https://github.com/remix-run/react-router/pull/12948))
|
|
81
317
|
- Add unstable support for splitting route modules in framework mode via `future.unstable_splitRouteModules` ([#11871](https://github.com/remix-run/react-router/pull/11871))
|
|
318
|
+
|
|
319
|
+
- Add `unstable_SerializesTo` brand type for library authors to register types serializable by React Router's streaming format (`turbo-stream`) ([`ab5b05b02`](https://github.com/remix-run/react-router/commit/ab5b05b02f99f062edb3c536c392197c88eb6c77))
|
|
320
|
+
|
|
82
321
|
- Align dev server behavior with static file server behavior when `ssr:false` is set ([#12948](https://github.com/remix-run/react-router/pull/12948))
|
|
83
322
|
|
|
84
323
|
- When no `prerender` config exists, only SSR down to the root `HydrateFallback` (SPA Mode)
|
|
@@ -86,6 +325,7 @@
|
|
|
86
325
|
- Return a 404 on `.data` requests to non-pre-rendered paths
|
|
87
326
|
|
|
88
327
|
- Improve prefetch performance of CSS side effects in framework mode ([#12889](https://github.com/remix-run/react-router/pull/12889))
|
|
328
|
+
|
|
89
329
|
- Disable Lazy Route Discovery for all `ssr:false` apps and not just "SPA Mode" because there is no runtime server to serve the search-param-configured `__manifest` requests ([#12894](https://github.com/remix-run/react-router/pull/12894))
|
|
90
330
|
|
|
91
331
|
- We previously only disabled this for "SPA Mode" which is `ssr:false` and no `prerender` config but we realized it should apply to all `ssr:false` apps, including those prerendering multiple pages
|