Skip to content

Commit 6a4b923

Browse files
committed
Merge branch 'brophdawg11/feat-middleware' into markdalgleish/client-middleware-chunk
2 parents 2336f3d + 979cf6c commit 6a4b923

File tree

207 files changed

+11260
-4656
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

207 files changed

+11260
-4656
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-router/dev": patch
3+
---
4+
5+
Fix support for custom client `build.rollupOptions.output.entryFileNames`

.changeset/cool-pillows-sing.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-router": patch
3+
---
4+
5+
Skip resource route flow in dev server in SPA mode

.changeset/dry-impalas-live.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-router/dev": patch
3+
---
4+
5+
Fix usage of `prerender` option when `serverBundles` option has been configured or provided by a preset, e.g. `vercelPreset` from `@vercel/react-router`

.changeset/fresh-buttons-sit.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/gold-insects-remain.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-router/dev": patch
3+
---
4+
5+
Fix support for custom `build.assetsDir`

.changeset/hip-jars-hunt.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-router/express": patch
3+
---
4+
5+
Update `express` `peerDependency` to include v5 (https://github.com/remix-run/react-router/pull/13064)

.changeset/lucky-icons-tap.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-router/dev": patch
3+
---
4+
5+
Remove unused dependencies

.changeset/middleware.md

Lines changed: 103 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,43 @@
22
"react-router": patch
33
---
44

5-
Support `middleware` on routes (unstable)
5+
Support middleware on routes (unstable)
66

7-
Routes can now define an array of middleware functions that will run sequentially before route handlers run. These functions accept the same arguments as `loader`/`action` plus an additional `next` function to run the remaining data pipeline. This allows middlewares to perform logic before and after handlers execute.
7+
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:
8+
9+
```ts
10+
import type { Config } from "@react-router/dev/config";
11+
import type { Future } from "react-router";
12+
13+
declare module "react-router" {
14+
interface Future {
15+
unstable_middleware: true; // 👈 Enable middleware types
16+
}
17+
}
18+
19+
export default {
20+
future: {
21+
unstable_middleware: true, // 👈 Enable middleware
22+
},
23+
} satisfies Config;
24+
```
25+
26+
⚠️ 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.
27+
28+
⚠️ Enabling middleware contains a breaking change to the `context` parameter passed to your `loader`/`action` functions - see below for more information.
29+
30+
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.
831

932
```tsx
1033
// Framework mode
11-
export const unstable_middleware = [serverLogger, serverAuth];
12-
export const unstable_clientMiddleware = [clientLogger];
34+
export const unstable_middleware = [serverLogger, serverAuth]; // server
35+
export const unstable_clientMiddleware = [clientLogger]; // client
1336

1437
// Library mode
1538
const routes = [
1639
{
1740
path: "/",
41+
// Middlewares are client-side for library mode SPA's
1842
unstable_middleware: [clientLogger, clientAuth],
1943
loader: rootLoader,
2044
Component: Root,
@@ -25,33 +49,29 @@ const routes = [
2549
Here's a simple example of a client-side logging middleware that can be placed on the root route:
2650

2751
```tsx
28-
async function clientLogger({
29-
request,
30-
params,
31-
context,
32-
next,
33-
}: Route.ClientMiddlewareArgs) {
52+
const clientLogger: Route.unstable_ClientMiddlewareFunction = async (
53+
{ request },
54+
next
55+
) => {
3456
let start = performance.now();
3557

3658
// Run the remaining middlewares and all route loaders
3759
await next();
3860

3961
let duration = performance.now() - start;
4062
console.log(`Navigated to ${request.url} (${duration}ms)`);
41-
}
63+
};
4264
```
4365

4466
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`.
4567

4668
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()`.
4769

4870
```tsx
49-
async function serverLogger({
50-
request,
51-
params,
52-
context,
53-
next,
54-
}: Route.MiddlewareArgs) {
71+
const serverLogger: Route.unstable_MiddlewareFunction = async (
72+
{ request, params, context },
73+
next
74+
) => {
5575
let start = performance.now();
5676

5777
// 👇 Grab the response here
@@ -60,31 +80,37 @@ async function serverLogger({
6080
let duration = performance.now() - start;
6181
console.log(`Navigated to ${request.url} (${duration}ms)`);
6282

63-
// 👇 And return it here
83+
// 👇 And return it here (optional if you don't modify the response)
6484
return res;
65-
}
85+
};
6686
```
6787

6888
You can throw a `redirect` from a middleware to short circuit any remaining processing:
6989

7090
```tsx
71-
function serverAuth({ request, params, context, next }: Route.MiddlewareArgs) {
72-
let user = context.session.get("user");
91+
import { sessionContext } from "../context";
92+
const serverAuth: Route.unstable_MiddlewareFunction = (
93+
{ request, params, context },
94+
next
95+
) => {
96+
let session = context.get(sessionContext);
97+
let user = session.get("user");
7398
if (!user) {
74-
context.session.set("returnTo", request.url);
99+
session.set("returnTo", request.url);
75100
throw redirect("/login", 302);
76101
}
77-
context.user = user;
78-
// No need to call next() if you don't need to do any post processing
79-
}
102+
};
80103
```
81104

82105
_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`._
83106

84107
Here's another example of using a server middleware to detect 404s and check the CMS for a redirect:
85108

86109
```tsx
87-
async function redirects({ request, next }: Route.MiddlewareArgs) {
110+
const redirects: Route.unstable_MiddlewareFunction = async ({
111+
request,
112+
next,
113+
}) => {
88114
// attempt to handle the request
89115
let res = await next();
90116

@@ -98,5 +124,56 @@ async function redirects({ request, next }: Route.MiddlewareArgs) {
98124
}
99125

100126
return res;
127+
};
128+
```
129+
130+
**`context` parameter**
131+
132+
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`):
133+
134+
```ts
135+
import { unstable_createContext } from "react-router";
136+
import { Route } from "./+types/root";
137+
import type { Session } from "./sessions.server";
138+
import { getSession } from "./sessions.server";
139+
140+
let sessionContext = unstable_createContext<Session>();
141+
142+
const sessionMiddleware: Route.unstable_MiddlewareFunction = ({
143+
context,
144+
request,
145+
}) => {
146+
let session = await getSession(request);
147+
context.set(sessionContext, session);
148+
// ^ must be of type Session
149+
};
150+
151+
// ... then in some downstream middleware
152+
const loggerMiddleware: Route.unstable_MiddlewareFunction = ({
153+
context,
154+
request,
155+
}) => {
156+
let session = context.get(sessionContext);
157+
// ^ typeof Session
158+
console.log(session.get("userId"), request.method, request.url);
159+
};
160+
161+
// ... or some downstream loader
162+
export function loader({ context }: Route.LoaderArgs) {
163+
let session = context.get(sessionContext);
164+
let profile = await getProfile(session.get("userId"));
165+
return { profile };
166+
}
167+
```
168+
169+
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>`):
170+
171+
```ts
172+
let adapterContext = unstable_createContext<MyAdapterContext>();
173+
174+
function getLoadContext(req, res): unstable_InitialContext {
175+
let map = new Map();
176+
map.set(adapterContext, getAdapterContext(req));
177+
return map;
101178
}
102179
```

.changeset/modern-forks-ring.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-router/dev": patch
3+
---
4+
5+
Stub all routes except root in "SPA Mode" server builds to avoid issues when route modules or their dependencies import non-SSR-friendly modules

.changeset/new-houses-hug.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-router/dev": patch
3+
---
4+
5+
Fix errors with `future.unstable_viteEnvironmentApi` when the `ssr` environment has been configured by another plugin to be a custom `Vite.DevEnvironment` rather than the default `Vite.RunnableDevEnvironment`

0 commit comments

Comments
 (0)