You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/how-to/middleware.md
+41-18Lines changed: 41 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,8 +9,6 @@ title: Middleware
9
9
<br/>
10
10
<br/>
11
11
12
-
<docs-info>In Framework Mode, you must opt-into middleware via the [`future.v8_middleware`][future-flags] flag because it contains a minor [breaking change][getloadcontext] to the `getLoadContext` function and the loader/action `context` parameter.</docs-info>
13
-
14
12
Middleware allows you to run code before and after the [`Response`][Response] generation for the matched path. This enables [common patterns][common-patterns] like authentication, logging, error handling, and data preprocessing in a reusable way.
15
13
16
14
Middleware runs in a nested chain, executing from parent routes to child routes on the way "down" to your route handlers, then from child routes back to parent routes on the way "up" after a [`Response`][Response] is generated.
@@ -132,12 +130,27 @@ function getLoadContext(req, res) {
132
130
133
131
## Quick Start (Data Mode)
134
132
135
-
<docs-info>Note there is no future flag in Data Mode because you can opt-into middleware by adding it to your routes, no breaking changes exist that require a future flag.</docs-info>
133
+
### 1. TypeScript: augment `Future` for loader/action `context`
136
134
137
-
### 1. Create a context
135
+
In order to properly type your `context` param in your `loader`/`action`/`middleware` functions, you will need a small module augmentation to override the default context type of `any`:
138
136
139
-
Middleware uses a `context` provider instance to provide data down the middleware chain.
140
-
You can create type-safe context objects using [`createContext`][createContext]:
137
+
```ts
138
+
// src/react-router.d.ts
139
+
140
+
import"react-router";
141
+
142
+
declaremodule"react-router" {
143
+
interfaceFuture {
144
+
v8_middleware:true;
145
+
}
146
+
}
147
+
```
148
+
149
+
Without this, `context` stays loosely typed even when middleware is enabled at runtime.
150
+
151
+
### 2. Create a context
152
+
153
+
Middleware uses a `context` provider to pass data through the middleware chain into loaders and actions. Create typed context with [`createContext`][createContext]:
141
154
142
155
```ts
143
156
import { createContext } from"react-router";
@@ -146,10 +159,16 @@ import type { User } from "~/types";
@@ -187,15 +206,15 @@ async function authMiddleware({ context }) {
187
206
context.set(userContext, user);
188
207
}
189
208
190
-
exportasyncfunctionprofileLoader({
209
+
exportasyncfunctiondashboardLoader({
191
210
context,
192
-
}:Route.LoaderArgs) {
211
+
}:LoaderFunctionArgs) {
193
212
const user =context.get(userContext);
194
213
const profile =awaitgetProfile(user);
195
214
return { profile };
196
215
}
197
216
198
-
exportdefaultfunctionProfile() {
217
+
exportdefaultfunctionDashboard() {
199
218
let loaderData =useLoaderData();
200
219
return (
201
220
<div>
@@ -206,9 +225,9 @@ export default function Profile() {
206
225
}
207
226
```
208
227
209
-
### 3. Add a `getContext` function (optional)
228
+
### 4. Add a `getContext` function (optional)
210
229
211
-
If you wish to include a base context on all navigations/fetches, you can add an [`getContext`][getContext]function to your router. This will be called to populate a fresh context on every navigation/fetch.
230
+
To seed every navigation or fetcher call with shared values, pass [`getContext`][getContext]when creating the router:
<docs-info>This API exists to mirror the `getLoadContext` API on the server in Framework Mode, which exists as a way to hand off values from your HTTP server to the React Router handler. This [`getContext`][getContext] API can be used to hand off global values from the [`window`][window]/[`document`][document] to React Router, but because they're all running in the same context (the browser), you can achieve effectively the same behavior with root route middleware. Therefore, you may not need this API the same way you would on the server - but it's provided for consistency.</docs-warning>
244
+
<docs-info>This mirrors Framework mode’s server-side [`getLoadContext`][getloadcontext]. In the browser, root `middleware`can often do the same job, but `getContext` is available when you want to seed every request up front.</docs-info>
226
245
227
246
## Core Concepts
228
247
@@ -250,7 +269,7 @@ Client middleware runs in the browser in framework and data mode for client-side
Copy file name to clipboardExpand all lines: docs/how-to/react-server-components.md
+60-43Lines changed: 60 additions & 43 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -77,7 +77,7 @@ export default defineConfig({
77
77
78
78
### Build Output
79
79
80
-
The RSC Framework Mode server build file (`build/server/index.js`) now exports a `default` request handler function (`(request: Request) => Promise<Response>`) for document/data requests.
80
+
The RSC Framework Mode server build file (`build/server/index.js`) exports a `default` request handler function (`(request: Request) => Promise<Response>`) for document/data requests.
81
81
82
82
If needed, you can convert this into a [standard Node.js request listener][node-request-listener] for use with Node's built-in `http.createServer` function (or anything that supports it, e.g. [Express][express]) by using the `createRequestListener` function from [@remix-run/node-fetch-server][node-fetch-server].
83
83
@@ -104,7 +104,7 @@ app.listen(3000);
104
104
105
105
### React Elements From Loaders/Actions
106
106
107
-
In RSC Framework Mode, loaders and actions can now return React elements along with other data. These elements will only ever be rendered on the server.
107
+
In RSC Framework Mode, loaders and actions can return React elements along with other data. These elements will only ever be rendered on the server.
108
108
109
109
```tsx
110
110
importtype { Route } from"./+types/route";
@@ -133,6 +133,8 @@ If you need to use client-only features (e.g. [Hooks][hooks], event handlers) wi
133
133
```tsx filename=src/routes/counter/counter.tsx
134
134
"use client";
135
135
136
+
import { useState } from"react";
137
+
136
138
exportfunction Counter() {
137
139
const [count, setCount] =useState(0);
138
140
return (
@@ -173,7 +175,9 @@ export default function Route({
173
175
174
176
### Route Server Components
175
177
176
-
If a route exports a `ServerComponent` instead of the typical `default` component export, this will be a server component rather than the usual client component. A default export and `ServerComponent` can not both be exported from the same route module, but you can still export client-only annotations like `clientLoader` and `clientAction` alongside a `ServerComponent`, along with any other component exports such as `ErrorBoundary` or `Layout`.
178
+
If a route exports a `ServerComponent` instead of the typical `default` component export, the route renders on the server instead of the client. A route module cannot export both `default` and `ServerComponent`.
179
+
180
+
You can still export client-only annotations like `clientLoader` and `clientAction` alongside a `ServerComponent`. The other route module component exports follow the same client/server split: `ErrorBoundary`, `Layout`, and `HydrateFallback` are client components, while `ServerErrorBoundary`, `ServerLayout`, and `ServerHydrateFallback` render on the server.
177
181
178
182
The following route module components have their own mutually exclusive server component counterparts:
179
183
@@ -213,6 +217,8 @@ If you need to use client-only features (e.g. [Hooks][hooks], event handlers) wi
213
217
```tsx filename=src/routes/counter/counter.tsx
214
218
"use client";
215
219
220
+
import { useState } from"react";
221
+
216
222
exportfunction Counter() {
217
223
const [count, setCount] =useState(0);
218
224
return (
@@ -287,6 +293,8 @@ The plugin will automatically detect custom entry files in your `app` directory:
287
293
288
294
If these files are not found, React Router will use the default entries provided by the framework.
289
295
296
+
If you want to inspect the generated defaults before overriding them, you can also use `react-router reveal entry.client`, `react-router reveal entry.rsc`, and `react-router reveal entry.ssr`.
297
+
290
298
#### Basic Override Pattern
291
299
292
300
You can create a custom entry file that wraps or extends the default behavior. For example, to add custom logging to the RSC entry:
@@ -371,14 +379,11 @@ When copying default entries, make sure to maintain the required exports:
371
379
372
380
### Unsupported Config Options
373
381
374
-
For the initial unstable release, the following options from `react-router.config.ts` are not yet supported in RSC Framework Mode:
382
+
The following options from `react-router.config.ts` are not currently supported in RSC Framework Mode:
375
383
376
384
-`buildEnd`
377
-
-`prerender`
378
385
-`presets`
379
-
-`routeDiscovery`
380
386
-`serverBundles`
381
-
-`ssr: false` (SPA Mode)
382
387
-`future.v8_splitRouteModules`
383
388
-`future.unstable_subResourceIntegrity`
384
389
@@ -403,11 +408,13 @@ matchRSCServerRequest({
403
408
});
404
409
```
405
410
406
-
While you can define components inline, we recommend using the `lazy()` option and defining [Route Modules][route-module] for both startup performance and code organization
411
+
While you can define components inline, we recommend using the `lazy()` option and defining [Route Modules][route-module] for both startup performance and code organization.
407
412
408
413
<docs-info>
409
414
410
-
The [Route Module API][route-module] up until now has been a [Framework Mode][framework-mode] only feature. However, the `lazy` field of the RSC route config expects the same exports as the Route Module exports, unifying the APIs even further.
415
+
The `lazy` field of the RSC route config expects the same exports as the [Route Module API][route-module], which keeps the route-module shape consistent across [Framework Mode][framework-mode] and RSC Data Mode.
416
+
417
+
That includes exports like `loader`, `action`, `meta`, `links`, `headers`, `ErrorBoundary`, `HydrateFallback`, and the client annotations.
411
418
412
419
</docs-info>
413
420
@@ -542,6 +549,10 @@ export function clientAction() {}
542
549
exportfunction clientLoader() {}
543
550
544
551
exportfunction shouldRevalidate() {}
552
+
553
+
exportdefaultfunction ClientRoot() {
554
+
return <p>Client route</p>;
555
+
}
545
556
```
546
557
547
558
We can then re-export these from our lazy loaded route module:
@@ -551,7 +562,7 @@ export {
551
562
clientAction,
552
563
clientLoader,
553
564
shouldRevalidate,
554
-
} from"./route.client";
565
+
} from"./client";
555
566
556
567
exportdefaultfunction Root() {
557
568
// ...
@@ -566,7 +577,7 @@ export {
566
577
clientAction,
567
578
clientLoader,
568
579
shouldRevalidate,
569
-
} from"./route.client";
580
+
} from"./client";
570
581
571
582
exportdefaultfunction Root() {
572
583
// Adding a Server Component at the root is required by bundlers
@@ -721,8 +732,12 @@ export async function generateHTML(
0 commit comments