diff --git a/.changeset/shy-lemons-boil.md b/.changeset/shy-lemons-boil.md new file mode 100644 index 0000000000..56c114950b --- /dev/null +++ b/.changeset/shy-lemons-boil.md @@ -0,0 +1,10 @@ +--- +"@react-router/cloudflare": minor +"@react-router/architect": minor +"@react-router/express": minor +"@react-router/node": minor +"@react-router/dev": minor +"react-router": minor +--- + +Stabilize middleware and context APIs diff --git a/docs/community/api-development-strategy.md b/docs/community/api-development-strategy.md index c4c6afb1b5..bfb5cd64ad 100644 --- a/docs/community/api-development-strategy.md +++ b/docs/community/api-development-strategy.md @@ -6,7 +6,7 @@ title: API Development Strategy React Router is foundational to your application. We want to make sure that upgrading to new major versions is as smooth as possible while still allowing us to adjust and enhance the behavior and API as the React ecosystem advances. -Our strategy and motivations are discussed in more detail in our [Future Flags][future-flags-blog-post] blog post. +Our strategy and motivations are discussed in more detail in our [Future Flags][future-flags-blog-post] blog post and our [Open Governance Model][governance]. ## Future Flags @@ -36,10 +36,9 @@ To learn about current unstable flags, keep an eye on the [CHANGELOG](../start/c ### Example New Feature Flow -The decision flow for a new feature looks something like this (note this diagram is in relation to Remix v1/v2 but applies to React Router v6/v7 as well): +The decision flow for a new feature looks something like this: -![Flowchart of the decision process for how to introduce a new feature][feature-flowchart] +Flowchart of the decision process for how to introduce a new feature [future-flags-blog-post]: https://remix.run/blog/future-flags -[feature-flowchart]: https://remix.run/docs-images/feature-flowchart.png -[picking-a-router]: ../routers/picking-a-router +[governance]: https://github.com/remix-run/react-router/blob/main/GOVERNANCE.md#new-feature-process diff --git a/docs/how-to/middleware.md b/docs/how-to/middleware.md index be7e84acfa..a3554ede83 100644 --- a/docs/how-to/middleware.md +++ b/docs/how-to/middleware.md @@ -1,6 +1,5 @@ --- title: Middleware -unstable: true --- # Middleware @@ -10,7 +9,7 @@ unstable: true

-The middleware feature is currently experimental and subject to breaking changes. Use the `future.unstable_middleware` flag to enable it. +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. 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. @@ -41,7 +40,7 @@ import type { Config } from "@react-router/dev/config"; export default { future: { - unstable_middleware: true, + v8_middleware: true, }, } satisfies Config; ``` @@ -51,14 +50,13 @@ export default { ### 2. Create a context Middleware uses a `context` provider instance to provide data down the middleware chain. -You can create type-safe context objects using [`unstable_createContext`][createContext]: +You can create type-safe context objects using [`createContext`][createContext]: ```ts filename=app/context.ts -import { unstable_createContext } from "react-router"; +import { createContext } from "react-router"; import type { User } from "~/types"; -export const userContext = - unstable_createContext(null); +export const userContext = createContext(null); ``` ### 3. Export middleware from your routes @@ -76,8 +74,9 @@ async function authMiddleware({ request, context }) { context.set(userContext, user); } -export const unstable_middleware: Route.unstable_MiddlewareFunction[] = - [authMiddleware]; +export const middleware: Route.MiddlewareFunction[] = [ + authMiddleware, +]; // Client-side timing middleware async function timingMiddleware({ context }, next) { @@ -87,7 +86,7 @@ async function timingMiddleware({ context }, next) { console.log(`Navigation took ${duration}ms`); } -export const unstable_clientMiddleware: Route.unstable_ClientMiddlewareFunction[] = +export const clientMiddleware: Route.ClientMiddlewareFunction[] = [timingMiddleware]; export async function loader({ @@ -112,20 +111,20 @@ export default function Dashboard({ ### 4. Update your `getLoadContext` function (if applicable) -If you're using a custom server and a `getLoadContext` function, you will need to update your implementation to return an instance of [`unstable_RouterContextProvider`][RouterContextProvider], instead of a JavaScript object: +If you're using a custom server and a `getLoadContext` function, you will need to update your implementation to return an instance of [`RouterContextProvider`][RouterContextProvider], instead of a JavaScript object: ```diff +import { -+ unstable_createContext, -+ unstable_RouterContextProvider, ++ createContext, ++ RouterContextProvider, +} from "react-router"; import { createDb } from "./db"; -+const dbContext = unstable_createContext(); ++const dbContext = createContext(); function getLoadContext(req, res) { - return { db: createDb() }; -+ const context = new unstable_RouterContextProvider(); ++ const context = new RouterContextProvider(); + context.set(dbContext, createDb()); + return context; } @@ -138,14 +137,13 @@ function getLoadContext(req, res) { ### 1. Create a context Middleware uses a `context` provider instance to provide data down the middleware chain. -You can create type-safe context objects using [`unstable_createContext`][createContext]: +You can create type-safe context objects using [`createContext`][createContext]: ```ts -import { unstable_createContext } from "react-router"; +import { createContext } from "react-router"; import type { User } from "~/types"; -export const userContext = - unstable_createContext(null); +export const userContext = createContext(null); ``` ### 2. Add middleware to your routes @@ -157,12 +155,12 @@ import { userContext } from "~/context"; const routes = [ { path: "/", - unstable_middleware: [timingMiddleware], // 👈 + middleware: [timingMiddleware], // 👈 Component: Root, children: [ { path: "profile", - unstable_middleware: [authMiddleware], // 👈 + middleware: [authMiddleware], // 👈 loader: profileLoader, Component: Profile, }, @@ -208,23 +206,23 @@ export default function Profile() { } ``` -### 3. Add an `unstable_getContext` function (optional) +### 3. Add a `getContext` function (optional) -If you wish to include a base context on all navigations/fetches, you can add an [`unstable_getContext`][getContext] function to your router. This will be called to populate a fresh context on every navigation/fetch. +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. ```tsx -let sessionContext = unstable_createContext(); +let sessionContext = createContext(); const router = createBrowserRouter(routes, { - unstable_getContext() { - let context = new unstable_RouterContextProvider(); + getContext() { + let context = new RouterContextProvider(); context.set(sessionContext, getSession()); return context; }, }); ``` -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 [`unstable_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. +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. ## Core Concepts @@ -241,8 +239,9 @@ async function serverMiddleware({ request }, next) { } // Framework mode only -export const unstable_middleware: Route.unstable_MiddlewareFunction[] = - [serverMiddleware]; +export const middleware: Route.MiddlewareFunction[] = [ + serverMiddleware, +]; ``` Client middleware runs in the browser in framework and data mode for client-side navigations and fetcher calls. Client middleware differs from server middleware because there's no HTTP Request, so it doesn't have a `Response` to bubble up. In most cases, you can just ignore the return value from `next` and return nothing from your middleware on the client: @@ -255,13 +254,13 @@ async function clientMiddleware({ request }, next) { } // Framework mode -export const unstable_clientMiddleware: Route.unstable_MiddlewareFunction[] = +export const clientMiddleware: Route.ClientMiddlewareFunction[] = [clientMiddleware]; // Or, Data mode const route = { path: "/", - unstable_middleware: [clientMiddleware], + middleware: [clientMiddleware], loader: rootLoader, Component: Root, }; @@ -326,8 +325,9 @@ async function loggingMiddleware({ request }, next) { return response; } -export const unstable_middleware: Route.unstable_MiddlewareFunction[] = - [loggingMiddleware]; +export const middleware: Route.MiddlewareFunction[] = [ + loggingMiddleware, +]; ``` However, there may be cases where you _want_ to run certain server middlewares on _every_ client-navigation - even if no `loader` exists. For example, a form in the authenticated section of your site that doesn't require a `loader` but you'd rather use auth middleware to redirect users away before they fill out the form — rather than when they submit to the `action`. If your middleware meets these criteria, then you can put a `loader` on the route that contains the middleware to force it to always call the server for client-side navigations involving that route. @@ -339,8 +339,9 @@ function authMiddleware({ request }, next) { } } -export const unstable_middleware: Route.unstable_MiddlewareFunction[] = - [authMiddleware]; +export const middleware: Route.MiddlewareFunction[] = [ + authMiddleware, +]; // By adding a `loader`, we force the `authMiddleware` to run on every // client-side navigation involving this route. @@ -359,8 +360,8 @@ The new context system provides type safety and prevents naming conflicts and al ```ts // ✅ Type-safe -import { unstable_createContext } from "react-router"; -const userContext = unstable_createContext(); +import { createContext } from "react-router"; +const userContext = createContext(); // Later in middleware/`loader`s context.set(userContext, user); // Must be `User` type @@ -401,15 +402,14 @@ export function getUser() { ```tsx filename=app/root.tsx import { provideUser } from "./user-context"; -export const unstable_middleware: Route.unstable_MiddlewareFunction[] = - [ - async ({ request, context }, next) => { - return provideUser(request, async () => { - let res = await next(); - return res; - }); - }, - ]; +export const middleware: Route.MiddlewareFunction[] = [ + async ({ request, context }, next) => { + return provideUser(request, async () => { + let res = await next(); + return res; + }); + }, +]; ``` ```tsx filename=app/routes/_index.tsx @@ -466,27 +466,25 @@ React Router contains built-in error handling via the route [`ErrorBoundary`][Er This behavior is important to allow middleware patterns such as automatically setting required headers on outgoing responses (i.e., committing a session) from a root `middleware`. If any error from a `middleware` caused `next()` to `throw`, we'd miss the execution of ancestor middlewares on the way out and those required headers wouldn't be set. ```tsx filename=routes/parent.tsx -export const unstable_middleware: Route.unstable_MiddlewareFunction[] = - [ - async (_, next) => { - let res = await next(); - // ^ res.status = 500 - // This response contains the ErrorBoundary - return res; - }, - ]; +export const middleware: Route.MiddlewareFunction[] = [ + async (_, next) => { + let res = await next(); + // ^ res.status = 500 + // This response contains the ErrorBoundary + return res; + }, +]; ``` ```tsx filename=routes/parent.child.tsx -export const unstable_middleware: Route.unstable_MiddlewareFunction[] = - [ - async (_, next) => { - let res = await next(); - // ^ res.status = 200 - // This response contains the successful UI render - throw new Error("Uh oh, something went wrong!"); - }, - ]; +export const middleware: Route.MiddlewareFunction[] = [ + async (_, next) => { + let res = await next(); + // ^ res.status = 200 + // This response contains the successful UI render + throw new Error("Uh oh, something went wrong!"); + }, +]; ``` ## Changes to `getLoadContext`/`AppLoadContext` @@ -497,31 +495,31 @@ Middleware introduces a breaking change to the `context` parameter generated by Middleware needs an equivalent `context` on the client for `clientMiddleware`, but we didn't want to duplicate this pattern from the server that we already weren't thrilled with, so we decided to introduce a new API where we could tackle type-safety. -When opting into middleware, the `context` parameter changes to an instance of [`unstable_RouterContextProvider`][RouterContextProvider]: +When opting into middleware, the `context` parameter changes to an instance of [`RouterContextProvider`][RouterContextProvider]: ```ts -let dbContext = unstable_createContext(); -let context = new unstable_RouterContextProvider(); +let dbContext = createContext(); +let context = new RouterContextProvider(); context.set(dbContext, getDb()); // ^ type-safe let db = context.get(dbContext); // ^ Database ``` -If you're using a custom server and a `getLoadContext` function, you will need to update your implementation to return an instance of [`unstable_RouterContextProvider`][RouterContextProvider], instead of a plain JavaScript object: +If you're using a custom server and a `getLoadContext` function, you will need to update your implementation to return an instance of [`RouterContextProvider`][RouterContextProvider], instead of a plain JavaScript object: ```diff +import { -+ unstable_createContext, -+ unstable_RouterContextProvider, ++ createContext, ++ RouterContextProvider, +} from "react-router"; import { createDb } from "./db"; -+const dbContext = unstable_createContext(); ++const dbContext = createContext(); function getLoadContext(req, res) { - return { db: createDb() }; -+ const context = new unstable_RouterContextProvider(); ++ const context = new RouterContextProvider(); + context.set(dbContext, createDb()); + return context; } @@ -529,12 +527,12 @@ function getLoadContext(req, res) { ### Migration from `AppLoadContext` -If you're currently using `AppLoadContext`, you can migrate incrementally by using your existing module augmentation to augment [`unstable_RouterContextProvider`][RouterContextProvider] instead of `AppLoadContext`. Then, update your `getLoadContext` function to return an instance of [`unstable_RouterContextProvider`][RouterContextProvider]: +If you're currently using `AppLoadContext`, you can migrate incrementally by using your existing module augmentation to augment [`RouterContextProvider`][RouterContextProvider] instead of `AppLoadContext`. Then, update your `getLoadContext` function to return an instance of [`RouterContextProvider`][RouterContextProvider]: ```diff declare module "react-router" { - interface AppLoadContext { -+ interface unstable_RouterContextProvider { ++ interface RouterContextProvider { db: Database; user: User; } @@ -543,7 +541,7 @@ declare module "react-router" { function getLoadContext() { const loadContext = {...}; - return loadContext; -+ let context = new unstable_RouterContextProvider(); ++ let context = new RouterContextProvider(); + Object.assign(context, loadContext); + return context; } @@ -553,7 +551,7 @@ This allows you to leave your `action`s/`loader`s untouched during initial adopt This approach is only intended to be used as a migration strategy when adopting middleware in React Router v7, allowing you to incrementally migrate to `context.set`/`context.get`. It is not safe to assume this approach will work in the next major version of React Router. -The [`unstable_RouterContextProvider`][RouterContextProvider] class is also used for the client-side `context` parameter via `` and ``. Since `AppLoadContext` is primarily intended as a hand-off from your HTTP server into the React Router handlers, you need to be aware that these augmented fields will not be available in `clientMiddleware`, `clientLoader`, or `clientAction` functions even thought TypeScript will tell you they are (unless, of course, you provide the fields via `unstable_getContext` on the client). +The [`RouterContextProvider`][RouterContextProvider] class is also used for the client-side `context` parameter via `` and ``. Since `AppLoadContext` is primarily intended as a hand-off from your HTTP server into the React Router handlers, you need to be aware that these augmented fields will not be available in `clientMiddleware`, `clientLoader`, or `clientAction` functions even thought TypeScript will tell you they are (unless, of course, you provide the fields via `getContext` on the client). ## Common Patterns @@ -583,8 +581,9 @@ export const authMiddleware = async ({ ```tsx filename=app/routes/protected.tsx import { authMiddleware } from "~/middleware/auth"; -export const unstable_middleware: Route.unstable_MiddlewareFunction[] = - [authMiddleware]; +export const middleware: Route.MiddlewareFunction[] = [ + authMiddleware, +]; export async function loader({ context, @@ -666,36 +665,34 @@ export const headersMiddleware = async ( ### Conditional Middleware ```tsx -export const unstable_middleware: Route.unstable_MiddlewareFunction[] = - [ - async ({ request, context }, next) => { - // Only run auth for POST requests - if (request.method === "POST") { - await ensureAuthenticated(request, context); - } - return next(); - }, - ]; +export const middleware: Route.MiddlewareFunction[] = [ + async ({ request, context }, next) => { + // Only run auth for POST requests + if (request.method === "POST") { + await ensureAuthenticated(request, context); + } + return next(); + }, +]; ``` ### Sharing Context Between `action` and `loader` ```tsx -const sharedDataContext = unstable_createContext(); - -export const unstable_middleware: Route.unstable_MiddlewareFunction[] = - [ - async ({ request, context }, next) => { - if (request.method === "POST") { - // Set data during action phase - context.set( - sharedDataContext, - await getExpensiveData(), - ); - } - return next(); - }, - ]; +const sharedDataContext = createContext(); + +export const middleware: Route.MiddlewareFunction[] = [ + async ({ request, context }, next) => { + if (request.method === "POST") { + // Set data during action phase + context.set( + sharedDataContext, + await getExpensiveData(), + ); + } + return next(); + }, +]; export async function action({ context, @@ -712,6 +709,7 @@ export async function loader({ } ``` +[future-flags]: ../upgrading/future [Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response [common-patterns]: #common-patterns [server-client]: #server-vs-client-middleware @@ -723,7 +721,7 @@ export async function loader({ [cms-redirect]: #cms-redirect-on-404 [createContext]: ../api/utils/createContext [RouterContextProvider]: ../api/utils/RouterContextProvider -[getContext]: ../api/data-routers/createBrowserRouter#optsunstable_getContext +[getContext]: ../api/data-routers/createBrowserRouter#optsgetContext [window]: https://developer.mozilla.org/en-US/docs/Web/API/Window [document]: https://developer.mozilla.org/en-US/docs/Web/API/Document [request]: https://developer.mozilla.org/en-US/docs/Web/API/Request diff --git a/docs/start/data/route-object.md b/docs/start/data/route-object.md index f933388ad7..40a8896fdb 100644 --- a/docs/start/data/route-object.md +++ b/docs/start/data/route-object.md @@ -54,7 +54,7 @@ function MyRouteComponent() { } ``` -## `unstable_middleware` +## `middleware` Route [middleware][middleware] runs sequentially before and after navigations. This gives you a singular place to do things like logging and authentication. The `next` function continues down the chain, and on the leaf route the `next` function executes the loaders/actions for the navigation. @@ -62,12 +62,12 @@ Route [middleware][middleware] runs sequentially before and after navigations. T createBrowserRouter([ { path: "/", - unstable_middleware: [loggingMiddleware], + middleware: [loggingMiddleware], loader: rootLoader, Component: Root, children: [{ path: 'auth', - unstable_middleware: [authMiddleware], + middleware: [authMiddleware], loader: authLoader, Component: Auth, children: [...] @@ -84,7 +84,7 @@ async function loggingMiddleware({ request }, next) { console.log(`Navigation completed in ${duration}ms`); } -const userContext = unstable_createContext(); +const userContext = createContext(); async function authMiddleware ({ context }) { const userId = getUserId(); diff --git a/docs/start/framework/route-module.md b/docs/start/framework/route-module.md index f613d83a32..3ed6b452e7 100644 --- a/docs/start/framework/route-module.md +++ b/docs/start/framework/route-module.md @@ -78,7 +78,7 @@ export default function MyRouteComponent({ } ``` -## `unstable_middleware` +## `middleware` Route [middleware][middleware] runs sequentially on the server before and after document and data requests. This gives you a singular place to do things like logging, @@ -103,7 +103,7 @@ async function loggingMiddleware( return response; } -export const unstable_middleware = [loggingMiddleware]; +export const middleware = [loggingMiddleware]; ``` Here's an example middleware to check for logged in users and set the user in @@ -125,19 +125,19 @@ async function authMiddleware ({ context.set(userContext, user); }; -export const unstable_middleware = [authMiddleware]; +export const middleware = [authMiddleware]; ``` Please make sure you understand [when middleware runs][when-middleware-runs] to make sure your application will behave the way you intend when adding middleware to your routes. See also: -- [`unstable_middleware` params][middleware-params] +- [`middleware` params][middleware-params] - [Middleware][middleware] -## `unstable_clientMiddleware` +## `clientMiddleware` -This is the client-side equivalent of `unstable_middleware` and runs in the browser during client navigations. The only difference from server middleware is that client middleware doesn't return Responses because they're not wrapping an HTTP request on the server. +This is the client-side equivalent of `middleware` and runs in the browser during client navigations. The only difference from server middleware is that client middleware doesn't return Responses because they're not wrapping an HTTP request on the server. Here's an example middleware to log requests on the client: @@ -158,9 +158,7 @@ async function loggingMiddleware( // ✅ No need to return anything } -export const unstable_clientMiddleware = [ - loggingMiddleware, -]; +export const clientMiddleware = [loggingMiddleware]; ``` See also: @@ -502,7 +500,7 @@ export function shouldRevalidate( Next: [Rendering Strategies](./rendering) -[middleware-params]: https://api.reactrouter.com/v7/types/react_router.unstable_MiddlewareFunction.html +[middleware-params]: https://api.reactrouter.com/v7/types/react_router.MiddlewareFunction.html [middleware]: ../../how-to/middleware [when-middleware-runs]: ../../how-to/middleware#when-middleware-runs [loader-params]: https://api.reactrouter.com/v7/interfaces/react_router.LoaderFunctionArgs diff --git a/docs/upgrading/future.md b/docs/upgrading/future.md index 2fcb46c0d4..682400de1b 100644 --- a/docs/upgrading/future.md +++ b/docs/upgrading/future.md @@ -9,4 +9,43 @@ This guide walks you through the process of adopting future flags in your React 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. -**There are no current future flags in React Router v7** +## Update to latest v7.x + +First update to the latest minor version of v7.x to have the latest future flags. You may see a number of deprecation warnings as you upgrade, which we'll cover below. + +👉 Update to latest v7 + +```sh +npm install react-router@7 @react-router/{dev,node,etc.}@7 +``` + +## `future.v8_middleware` + +[MODES: framework] + +
+
+ +**Background** + +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. + +👉 **Enable the Flag** + +```ts filename=react-router.config.ts +import type { Config } from "@react-router/dev/config"; + +export default { + future: { + v8_middleware: true, + }, +} satisfies Config; +``` + +**Update your Code** + +If you're using `react-router-serve`, then you should not need to make any updates to your code. + +You should only need to update your code if you are using the `context` parameter in `loader` and `action` functions. 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). + +[Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response diff --git a/integration/browser-entry-test.ts b/integration/browser-entry-test.ts index ae4e831296..37e1dbce47 100644 --- a/integration/browser-entry-test.ts +++ b/integration/browser-entry-test.ts @@ -87,20 +87,20 @@ test("allows users to pass a client side context to HydratedRouter", async ({ let fixture = await createFixture({ files: { "app/entry.client.tsx": js` - import { unstable_createContext, unstable_RouterContextProvider } from "react-router"; + import { createContext, RouterContextProvider } from "react-router"; import { HydratedRouter } from "react-router/dom"; import { startTransition, StrictMode } from "react"; import { hydrateRoot } from "react-dom/client"; - export const myContext = new unstable_createContext('foo'); + export const myContext = new createContext('foo'); startTransition(() => { hydrateRoot( document, { - return new unstable_RouterContextProvider([ + getContext={() => { + return new RouterContextProvider([ [myContext, 'bar'] ]); }} diff --git a/integration/helpers/rsc-parcel/src/browser.tsx b/integration/helpers/rsc-parcel/src/browser.tsx index 37f35708b0..d0c02387d1 100644 --- a/integration/helpers/rsc-parcel/src/browser.tsx +++ b/integration/helpers/rsc-parcel/src/browser.tsx @@ -15,7 +15,7 @@ import { setServerCallback, // @ts-expect-error - no types for this yet } from "react-server-dom-parcel/client"; -import { unstable_getContext } from "./config/unstable-get-context"; +import { getContext } from "./config/get-context"; // Create and set the callServer function to support post-hydration server actions. setServerCallback( @@ -39,7 +39,7 @@ createFromReadableStream(getRSCStream()).then((payload: RSCPayload) => { , { diff --git a/integration/helpers/rsc-parcel/src/config/unstable-get-context.ts b/integration/helpers/rsc-parcel/src/config/get-context.ts similarity index 57% rename from integration/helpers/rsc-parcel/src/config/unstable-get-context.ts rename to integration/helpers/rsc-parcel/src/config/get-context.ts index 2616a6a1b1..43ad6d9d54 100644 --- a/integration/helpers/rsc-parcel/src/config/unstable-get-context.ts +++ b/integration/helpers/rsc-parcel/src/config/get-context.ts @@ -1,2 +1,2 @@ // THIS FILE IS DESIGNED TO BE OVERRIDDEN IN TESTS IF NEEDED -export const unstable_getContext = undefined; +export const getContext = undefined; diff --git a/integration/helpers/rsc-vite/src/config/unstable-get-context.ts b/integration/helpers/rsc-vite/src/config/get-context.ts similarity index 57% rename from integration/helpers/rsc-vite/src/config/unstable-get-context.ts rename to integration/helpers/rsc-vite/src/config/get-context.ts index 2616a6a1b1..43ad6d9d54 100644 --- a/integration/helpers/rsc-vite/src/config/unstable-get-context.ts +++ b/integration/helpers/rsc-vite/src/config/get-context.ts @@ -1,2 +1,2 @@ // THIS FILE IS DESIGNED TO BE OVERRIDDEN IN TESTS IF NEEDED -export const unstable_getContext = undefined; +export const getContext = undefined; diff --git a/integration/helpers/rsc-vite/src/entry.browser.tsx b/integration/helpers/rsc-vite/src/entry.browser.tsx index 87d5effe24..d8f9df5a33 100644 --- a/integration/helpers/rsc-vite/src/entry.browser.tsx +++ b/integration/helpers/rsc-vite/src/entry.browser.tsx @@ -12,7 +12,7 @@ import { unstable_RSCHydratedRouter as RSCHydratedRouter, } from "react-router"; import type { unstable_RSCPayload as RSCPayload } from "react-router"; -import { unstable_getContext } from "./config/unstable-get-context"; +import { getContext } from "./config/get-context"; setServerCallback( createCallServer({ @@ -30,7 +30,7 @@ createFromReadableStream(getRSCStream()).then((payload) => { , ); diff --git a/integration/helpers/vite.ts b/integration/helpers/vite.ts index f6468c3b02..e2f8a86d69 100644 --- a/integration/helpers/vite.ts +++ b/integration/helpers/vite.ts @@ -30,7 +30,7 @@ export const reactRouterConfig = ({ appDirectory, splitRouteModules, viteEnvironmentApi, - middleware, + v8_middleware, routeDiscovery, }: { ssr?: boolean; @@ -41,7 +41,7 @@ export const reactRouterConfig = ({ Config["future"] >["unstable_splitRouteModules"]; viteEnvironmentApi?: boolean; - middleware?: boolean; + v8_middleware?: boolean; routeDiscovery?: Config["routeDiscovery"]; }) => { let config: Config = { @@ -53,7 +53,7 @@ export const reactRouterConfig = ({ future: { unstable_splitRouteModules: splitRouteModules, unstable_viteEnvironmentApi: viteEnvironmentApi, - unstable_middleware: middleware, + v8_middleware, }, }; diff --git a/integration/middleware-test.ts b/integration/middleware-test.ts index 34b31a9db4..1227f97ca0 100644 --- a/integration/middleware-test.ts +++ b/integration/middleware-test.ts @@ -101,7 +101,7 @@ test.describe("Middleware", () => { files: { "react-router.config.ts": reactRouterConfig({ ssr: false, - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -113,14 +113,14 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Link } from 'react-router' import { orderContext } from '../context' - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'a']); }, @@ -145,7 +145,7 @@ test.describe("Middleware", () => { "app/routes/about.tsx": js` import { orderContext } from '../context' - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'c']); }, @@ -191,7 +191,7 @@ test.describe("Middleware", () => { files: { "react-router.config.ts": reactRouterConfig({ ssr: false, - middleware: true, + v8_middleware: true, splitRouteModules: true, }), "vite.config.ts": js` @@ -204,14 +204,14 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Link } from 'react-router' import { orderContext } from '../context' - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'a']); }, @@ -236,7 +236,7 @@ test.describe("Middleware", () => { "app/routes/about.tsx": js` import { orderContext } from '../context' - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'c']); }, @@ -280,7 +280,7 @@ test.describe("Middleware", () => { files: { "react-router.config.ts": reactRouterConfig({ ssr: false, - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -292,14 +292,14 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Form } from 'react-router' import { orderContext } from '../context'; - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ request, context }) => { context.set(orderContext, ['a']); }, @@ -356,7 +356,7 @@ test.describe("Middleware", () => { files: { "react-router.config.ts": reactRouterConfig({ ssr: false, - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -376,7 +376,7 @@ test.describe("Middleware", () => { `, "app/routes/redirect.tsx": js` import { Link, redirect } from 'react-router' - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ request, context }) => { throw redirect('/target'); } ] export default function Component() { @@ -409,7 +409,7 @@ test.describe("Middleware", () => { files: { "react-router.config.ts": reactRouterConfig({ ssr: false, - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -429,7 +429,7 @@ test.describe("Middleware", () => { `, "app/routes/redirect.tsx": js` import { Link, redirect } from 'react-router' - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ async ({ request, context }, next) => { await next(); throw redirect('/target'); @@ -466,7 +466,7 @@ test.describe("Middleware", () => { files: { "react-router.config.ts": reactRouterConfig({ ssr: false, - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -485,7 +485,7 @@ test.describe("Middleware", () => { } `, "app/routes/broken.tsx": js` - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ async ({ request, context }, next) => { throw new Error('broken!'); } @@ -525,7 +525,7 @@ test.describe("Middleware", () => { files: { "react-router.config.ts": reactRouterConfig({ ssr: false, - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -544,7 +544,7 @@ test.describe("Middleware", () => { } `, "app/routes/broken.tsx": js` - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ async ({ request, context }, next) => { await next(); throw new Error('broken!'); @@ -595,7 +595,7 @@ test.describe("Middleware", () => { files: { "react-router.config.ts": reactRouterConfig({ ssr: false, - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -607,8 +607,8 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Link } from 'react-router' @@ -619,7 +619,7 @@ test.describe("Middleware", () => { "app/routes/a.tsx": js` import { Outlet } from 'react-router' import { orderContext } from '../context'; - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'a']); }, @@ -636,7 +636,7 @@ test.describe("Middleware", () => { "app/routes/a.b.tsx": js` import { Outlet } from 'react-router' import { orderContext } from '../context'; - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'b']); } @@ -678,7 +678,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -690,14 +690,14 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Link } from 'react-router' import { orderContext } from "../context";; - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'a']); }, @@ -721,7 +721,7 @@ test.describe("Middleware", () => { `, "app/routes/about.tsx": js` import { orderContext } from "../context";; - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, ['c']); // reset order from hydration }, @@ -765,7 +765,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, splitRouteModules: true, }), "vite.config.ts": js` @@ -778,14 +778,14 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Link } from 'react-router' import { orderContext } from "../context";; - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'a']); }, @@ -809,7 +809,7 @@ test.describe("Middleware", () => { `, "app/routes/about.tsx": js` import { orderContext } from "../context";; - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, ['c']); // reset order from hydration }, @@ -851,7 +851,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -865,7 +865,7 @@ test.describe("Middleware", () => { "app/routes/_index.tsx": js` import { Link } from 'react-router' - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { console.log('running index middleware') }, @@ -882,7 +882,7 @@ test.describe("Middleware", () => { `, "app/routes/about.tsx": js` import { Link } from 'react-router' - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { console.log('running about middleware') }, @@ -924,7 +924,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -936,14 +936,14 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Form } from 'react-router' import { orderContext } from "../context";; - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, ['a']); }, @@ -998,7 +998,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1018,7 +1018,7 @@ test.describe("Middleware", () => { `, "app/routes/redirect.tsx": js` import { Link, redirect } from 'react-router' - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ request, context }) => { throw redirect('/target'); } ] export default function Component() { @@ -1049,7 +1049,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1069,7 +1069,7 @@ test.describe("Middleware", () => { `, "app/routes/redirect.tsx": js` import { Link, redirect } from 'react-router' - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ async ({ request, context }, next) => { await next(); throw redirect('/target'); @@ -1104,7 +1104,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1123,7 +1123,7 @@ test.describe("Middleware", () => { } `, "app/routes/broken.tsx": js` - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ async ({ request, context }, next) => { throw new Error('broken!') } @@ -1161,7 +1161,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1181,7 +1181,7 @@ test.describe("Middleware", () => { `, "app/routes/broken.tsx": js` import { useRouteError } from 'react-router' - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ async ({ request, context }, next) => { await next(); throw new Error('broken!') @@ -1230,7 +1230,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1242,8 +1242,8 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Link } from 'react-router' @@ -1254,7 +1254,7 @@ test.describe("Middleware", () => { "app/routes/a.tsx": js` import { Outlet } from 'react-router' import { orderContext } from '../context'; - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, ['a']); } ]; @@ -1269,7 +1269,7 @@ test.describe("Middleware", () => { "app/routes/a.b.tsx": js` import { Outlet } from 'react-router' import { orderContext } from '../context'; - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'b']); }, @@ -1311,7 +1311,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1323,8 +1323,8 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const countContext = unstable_createContext({ + import { createContext } from 'react-router' + export const countContext = createContext({ parent: 0, child: 0, }); @@ -1341,7 +1341,7 @@ test.describe("Middleware", () => { export function loader() { return 'PARENT' } - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.get(countContext).parent++ }, ]; @@ -1366,7 +1366,7 @@ test.describe("Middleware", () => { export function loader() { return 'CHILD' } - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.get(countContext).child++ }, ]; @@ -1433,7 +1433,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1445,8 +1445,8 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const countContext = unstable_createContext({ + import { createContext } from 'react-router' + export const countContext = createContext({ parent: 0, child: 0, index: 0, @@ -1464,7 +1464,7 @@ test.describe("Middleware", () => { export function loader() { return 'PARENT' } - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.get(countContext).parent++ }, ]; export default function Component({ loaderData }) { @@ -1485,7 +1485,7 @@ test.describe("Middleware", () => { export function loader() { return 'CHILD' } - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.get(countContext).child++ }, ]; export default function Component({ loaderData }) { @@ -1506,7 +1506,7 @@ test.describe("Middleware", () => { export function loader() { return 'INDEX' } - export const unstable_clientMiddleware = [ + export const clientMiddleware = [ ({ context }) => { context.get(countContext).index++ }, ]; export async function clientLoader({ serverLoader, context }) { @@ -1595,7 +1595,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1607,14 +1607,14 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Link } from 'react-router' import { orderContext } from "../context";; - export const unstable_middleware = [ + export const middleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'a']); }, @@ -1638,7 +1638,7 @@ test.describe("Middleware", () => { `, "app/routes/about.tsx": js` import { orderContext } from "../context";; - export const unstable_middleware = [ + export const middleware = [ ({ context }) => { context.set(orderContext, ['c']); }, @@ -1686,7 +1686,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1700,7 +1700,7 @@ test.describe("Middleware", () => { "app/routes/parent.tsx": js` import { Link, Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ ({ request }) => { console.log('Running parent middleware', new URL(request.url).pathname) }, @@ -1718,7 +1718,7 @@ test.describe("Middleware", () => { } `, "app/routes/parent.a.tsx": js` - export const unstable_middleware = [ + export const middleware = [ ({ request }) => { console.log('Running A middleware', new URL(request.url).pathname) }, @@ -1729,7 +1729,7 @@ test.describe("Middleware", () => { } `, "app/routes/parent.b.tsx": js` - export const unstable_middleware = [ + export const middleware = [ ({ request }) => { console.log('Running B middleware', new URL(request.url).pathname) }, @@ -1768,7 +1768,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1780,14 +1780,14 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Form } from 'react-router' import { orderContext } from "../context";; - export const unstable_middleware = [ + export const middleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'a']); }, @@ -1842,7 +1842,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1862,7 +1862,7 @@ test.describe("Middleware", () => { `, "app/routes/redirect.tsx": js` import { Link, redirect } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ ({ request, context }) => { throw redirect('/target'); } ] export function loader() { @@ -1900,7 +1900,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1920,7 +1920,7 @@ test.describe("Middleware", () => { `, "app/routes/redirect.tsx": js` import { Link, redirect } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async ({ request, context }, next) => { await next(); throw redirect('/target'); @@ -1963,7 +1963,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -1976,7 +1976,7 @@ test.describe("Middleware", () => { `, "app/routes/redirect.tsx": js` import { Link, redirect } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async ({ request, context }, next) => { let res = await next(); // Should still be a normal redirect here, not yet encoded into @@ -2027,7 +2027,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -2047,7 +2047,7 @@ test.describe("Middleware", () => { } `, "app/routes/broken.tsx": js` - export const unstable_middleware = [ + export const middleware = [ async ({ request, context }, next) => { throw new Error('broken!'); } @@ -2086,7 +2086,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -2106,7 +2106,7 @@ test.describe("Middleware", () => { } `, "app/routes/broken.tsx": js` - export const unstable_middleware = [ + export const middleware = [ async ({ request, context }, next) => { throw new Error('broken!'); } @@ -2160,7 +2160,7 @@ test.describe("Middleware", () => { }); `, "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "app/entry.server.tsx": ENTRY_SERVER_WITH_HANDLE_ERROR, "app/routes/_index.tsx": js` @@ -2171,7 +2171,7 @@ test.describe("Middleware", () => { } `, "app/routes/broken.tsx": js` - export const unstable_middleware = [ + export const middleware = [ async ({ request, context }, next) => { await next(); throw new Error('broken!'); @@ -2220,7 +2220,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -2240,7 +2240,7 @@ test.describe("Middleware", () => { } `, "app/routes/broken.tsx": js` - export const unstable_middleware = [ + export const middleware = [ async ({ request, context }, next) => { await next() throw new Error('broken!'); @@ -2293,7 +2293,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -2314,7 +2314,7 @@ test.describe("Middleware", () => { "app/routes/a.tsx": js` import { Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async ({ context }, next) => { let res = await next(); res.headers.set('x-a', 'true'); @@ -2335,7 +2335,7 @@ test.describe("Middleware", () => { } `, "app/routes/a.b.tsx": js` - export const unstable_middleware = [ + export const middleware = [ async ({ context }, next) => { let res = await next(); throw new Error('broken!') @@ -2378,7 +2378,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -2399,7 +2399,7 @@ test.describe("Middleware", () => { "app/routes/a.tsx": js` import { Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async ({ context }, next) => { let res = await next(); res.headers.set('x-a', 'true'); @@ -2420,7 +2420,7 @@ test.describe("Middleware", () => { } `, "app/routes/a.b.tsx": js` - export const unstable_middleware = [ + export const middleware = [ async ({ context }, next) => { let res = await next(); throw new Error('broken!') @@ -2468,7 +2468,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -2515,7 +2515,7 @@ test.describe("Middleware", () => { `, "app/routes/a.b.c.d.tsx": js` import { Outlet } from 'react-router' - export const unstable_middleware = [() => { throw new Error("broken!") }] + export const middleware = [() => { throw new Error("broken!") }] export default function Component() { return } @@ -2559,7 +2559,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -2621,7 +2621,7 @@ test.describe("Middleware", () => { `, "app/routes/a.b.c.d.tsx": js` import { Outlet } from 'react-router' - export const unstable_middleware = [() => { throw new Error("broken!") }] + export const middleware = [() => { throw new Error("broken!") }] export const loader = () => null; export default function Component() { return @@ -2667,7 +2667,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -2686,7 +2686,7 @@ test.describe("Middleware", () => { `, "app/routes/a.tsx": js` import { Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async (_, next) => { let res = await next(); res.headers.set('x-a', 'true'); @@ -2702,7 +2702,7 @@ test.describe("Middleware", () => { `, "app/routes/a.b.tsx": js` import { Link, Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async (_, next) => { let res = await next(); res.headers.set('x-b', 'true'); @@ -2714,7 +2714,7 @@ test.describe("Middleware", () => { } `, "app/routes/a.b.c.tsx": js` - export const unstable_middleware = [(_, next) => { + export const middleware = [(_, next) => { throw new Error('C ERROR') }]; // Force middleware to run on client side navs @@ -2770,7 +2770,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -2789,7 +2789,7 @@ test.describe("Middleware", () => { `, "app/routes/a.tsx": js` import { Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async (_, next) => { let res = await next(); res.headers.set('x-a', 'true'); @@ -2814,7 +2814,7 @@ test.describe("Middleware", () => { `, "app/routes/a.b.tsx": js` import { Link, Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async (_, next) => { let res = await next(); res.headers.set('x-b', 'true'); @@ -2826,7 +2826,7 @@ test.describe("Middleware", () => { } `, "app/routes/a.b.c.tsx": js` - export const unstable_middleware = [async (_, next) => { + export const middleware = [async (_, next) => { let res = await next(); throw new Error('C ERROR') }]; @@ -2890,7 +2890,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -2910,7 +2910,7 @@ test.describe("Middleware", () => { `, "app/routes/a.tsx": js` import { Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async (_, next) => { let res = await next(); res.headers.set('x-a', 'true'); @@ -2935,7 +2935,7 @@ test.describe("Middleware", () => { `, "app/routes/a.b.tsx": js` import { Link, Outlet } from 'react-router' - export const unstable_middleware = [async (_, next) => { + export const middleware = [async (_, next) => { let res = await next(); throw new Error('B ERROR') }]; @@ -2944,7 +2944,7 @@ test.describe("Middleware", () => { } `, "app/routes/a.b.c.tsx": js` - export const unstable_middleware = [async (_, next) => { + export const middleware = [async (_, next) => { let res = await next(); throw new Error('C ERROR') }]; @@ -3021,7 +3021,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -3040,7 +3040,7 @@ test.describe("Middleware", () => { `, "app/routes/a.tsx": js` import { Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async (_, next) => { let res = await next(); res.headers.set('x-a', 'true'); @@ -3061,7 +3061,7 @@ test.describe("Middleware", () => { `, "app/routes/a.b.tsx": js` import { Link, Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async (_, next) => { let res = await next(); res.headers.set('x-b', 'true'); @@ -3074,7 +3074,7 @@ test.describe("Middleware", () => { `, "app/routes/a.b.c.tsx": js` import { data } from "react-router"; - export const unstable_middleware = [(_, next) => { + export const middleware = [(_, next) => { throw data('C ERROR', { status: 418, statusText: "I'm a teapot" }) }]; // Force middleware to run on client side navs @@ -3130,7 +3130,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -3149,7 +3149,7 @@ test.describe("Middleware", () => { `, "app/routes/a.tsx": js` import { Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async (_, next) => { let res = await next(); res.headers.set('x-a', 'true'); @@ -3174,7 +3174,7 @@ test.describe("Middleware", () => { `, "app/routes/a.b.tsx": js` import { Link, Outlet } from 'react-router' - export const unstable_middleware = [ + export const middleware = [ async (_, next) => { let res = await next(); res.headers.set('x-b', 'true'); @@ -3187,7 +3187,7 @@ test.describe("Middleware", () => { `, "app/routes/a.b.c.tsx": js` import { data } from "react-router"; - export const unstable_middleware = [async (_, next) => { + export const middleware = [async (_, next) => { let res = await next(); throw data('C ERROR', { status: 418, statusText: "I'm a teapot" }) }]; @@ -3248,7 +3248,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -3260,8 +3260,8 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Link } from 'react-router' @@ -3272,7 +3272,7 @@ test.describe("Middleware", () => { "app/routes/a.tsx": js` import { Outlet } from 'react-router' import { orderContext } from '../context'; - export const unstable_middleware = [ + export const middleware = [ ({ context }) => { context.set(orderContext, ['a']); }, ]; @@ -3297,7 +3297,7 @@ test.describe("Middleware", () => { "app/routes/a.b.tsx": js` import { Outlet } from 'react-router' import { orderContext } from '../context'; - export const unstable_middleware = [ + export const middleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'b']); }, @@ -3339,7 +3339,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -3351,8 +3351,8 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Link } from 'react-router' @@ -3363,7 +3363,7 @@ test.describe("Middleware", () => { "app/routes/a.tsx": js` import { Outlet } from 'react-router' import { orderContext } from '../context'; - export const unstable_middleware = [ + export const middleware = [ ({ context }) => { context.set(orderContext, ['a']); } ]; @@ -3378,7 +3378,7 @@ test.describe("Middleware", () => { "app/routes/a.b.tsx": js` import { Outlet } from 'react-router' import { orderContext } from '../context'; - export const unstable_middleware = [ + export const middleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'b']); }, @@ -3418,7 +3418,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -3430,8 +3430,8 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import { Link } from 'react-router' @@ -3442,7 +3442,7 @@ test.describe("Middleware", () => { "app/routes/a.tsx": js` import { Outlet } from 'react-router' import { orderContext } from '../context'; - export const unstable_middleware = [ + export const middleware = [ ({ context }) => { context.set(orderContext, ['a']); } ]; @@ -3457,7 +3457,7 @@ test.describe("Middleware", () => { "app/routes/a.b.tsx": js` import { Outlet } from 'react-router' import { orderContext } from '../context'; - export const unstable_middleware = [ + export const middleware = [ ({ context }) => { context.set(orderContext, [...context.get(orderContext), 'b']); }, @@ -3497,7 +3497,7 @@ test.describe("Middleware", () => { let fixture = await createFixture({ files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -3509,8 +3509,8 @@ test.describe("Middleware", () => { }); `, "app/context.ts": js` - import { unstable_createContext } from 'react-router' - export const orderContext = unstable_createContext([]); + import { createContext } from 'react-router' + export const orderContext = createContext([]); `, "app/routes/_index.tsx": js` import * as React from 'react' @@ -3544,7 +3544,7 @@ test.describe("Middleware", () => { `, "app/routes/a.tsx": js` import { orderContext } from '../context'; - export const unstable_middleware = [ + export const middleware = [ async ({ context }, next) => { context.set(orderContext, ['a']); let res = await next(); @@ -3555,7 +3555,7 @@ test.describe("Middleware", () => { `, "app/routes/a.b.tsx": js` import { orderContext } from '../context'; - export const unstable_middleware = [ + export const middleware = [ async ({ context }, next) => { context.set(orderContext, [...context.get(orderContext), 'b']); let res = await next(); @@ -3612,7 +3612,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -3625,7 +3625,7 @@ test.describe("Middleware", () => { `, "app/entry.server.tsx": ENTRY_SERVER_WITH_HANDLE_ERROR, "app/routes/a.tsx": js` - export const unstable_middleware = [ + export const middleware = [ async ({ context }, next) => { throw new Error("broken!"); }, @@ -3658,7 +3658,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -3671,7 +3671,7 @@ test.describe("Middleware", () => { `, "app/entry.server.tsx": ENTRY_SERVER_WITH_HANDLE_ERROR, "app/routes/a.tsx": js` - export const unstable_middleware = [ + export const middleware = [ async ({ context }, next) => { throw new Error("broken!"); }, @@ -3704,7 +3704,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -3717,7 +3717,7 @@ test.describe("Middleware", () => { `, "app/entry.server.tsx": ENTRY_SERVER_WITH_HANDLE_ERROR, "app/routes/a.tsx": js` - export const unstable_middleware = [ + export const middleware = [ async ({ context }, next) => { let res = await next() throw new Error("broken!"); @@ -3751,7 +3751,7 @@ test.describe("Middleware", () => { { files: { "react-router.config.ts": reactRouterConfig({ - middleware: true, + v8_middleware: true, }), "vite.config.ts": js` import { defineConfig } from "vite"; @@ -3764,7 +3764,7 @@ test.describe("Middleware", () => { `, "app/entry.server.tsx": ENTRY_SERVER_WITH_HANDLE_ERROR, "app/routes/a.tsx": js` - export const unstable_middleware = [ + export const middleware = [ async ({ context }, next) => { let res = await next(); throw new Error("broken!"); diff --git a/integration/resource-routes-test.ts b/integration/resource-routes-test.ts index 0718fe1c1c..0aafeda0d1 100644 --- a/integration/resource-routes-test.ts +++ b/integration/resource-routes-test.ts @@ -107,14 +107,14 @@ test.describe("loader in an app", async () => { `, "app/routes/return-data-through-middleware.tsx": js` import { data } from "react-router"; - export const unstable_middleware = [(_, next) => next()] + export const middleware = [(_, next) => next()] export let loader = () => { return data('Partial', { status: 207, headers: { 'X-Foo': 'Bar'} }); } `, "app/routes/throw-data-through-middleware.tsx": js` import { data } from "react-router"; - export const unstable_middleware = [(_, next) => next()] + export const middleware = [(_, next) => next()] export let loader = () => { throw data('Partial', { status: 207, headers: { 'X-Foo': 'Bar'} }); } diff --git a/integration/rsc/rsc-test.ts b/integration/rsc/rsc-test.ts index a8807d833c..265984b0ad 100644 --- a/integration/rsc/rsc-test.ts +++ b/integration/rsc/rsc-test.ts @@ -26,7 +26,7 @@ implementations.forEach((implementation) => { files: { "src/routes.ts": js` import type { unstable_RSCRouteConfig as RSCRouteConfig } from "react-router"; - + export const routes = [ { id: "root", @@ -297,7 +297,7 @@ implementations.forEach((implementation) => { files: { "src/routes.ts": js` import type { unstable_RSCRouteConfig as RSCRouteConfig } from "react-router"; - + export const routes = [ { id: "root", @@ -354,14 +354,14 @@ implementations.forEach((implementation) => { ] }, { - id: "unstable-get-context", - path: "unstable-get-context", - lazy: () => import("./routes/unstable-get-context/root"), + id: "get-context", + path: "get-context", + lazy: () => import("./routes/get-context/root"), children: [ { - id: "unstable-get-context.home", + id: "get-context.home", index: true, - lazy: () => import("./routes/unstable-get-context/home"), + lazy: () => import("./routes/get-context/home"), }, ] }, @@ -489,8 +489,8 @@ implementations.forEach((implementation) => { "src/routes/root.tsx": js` import { Links, Outlet, ScrollRestoration } from "react-router"; - - export const unstable_middleware = [ + + export const middleware = [ async (_, next) => { const response = await next(); return response.headers.set("x-test", "test"); @@ -520,32 +520,32 @@ implementations.forEach((implementation) => { `, "src/config/request-context.ts": js` - import { unstable_createContext, unstable_RouterContextProvider } from "react-router"; - - export const testContext = unstable_createContext("default-value"); - - export const requestContext = new unstable_RouterContextProvider( + import { createContext, RouterContextProvider } from "react-router"; + + export const testContext = createContext("default-value"); + + export const requestContext = new RouterContextProvider( new Map([[testContext, "test-context-value"]]) ); `, - "src/config/unstable-get-context.ts": js` + "src/config/get-context.ts": js` // THIS FILE OVERRIDES THE DEFAULT IMPLEMENTATION - import { unstable_createContext } from "react-router"; - - export const testContext = unstable_createContext("default-value"); - - export function unstable_getContext() { + import { createContext } from "react-router"; + + export const testContext = createContext("default-value"); + + export function getContext() { return new Map([[testContext, "client-context-value"]]); } `, "src/routes/soft-navigation/home.tsx": js` import { Link } from "react-router"; - + export function loader() { return { message: "Home Page Data" }; } - + export default function HomeRoute({ loaderData }) { return (
@@ -560,37 +560,37 @@ implementations.forEach((implementation) => { export function loader() { return { count: 1 }; } - + export { default } from "./dashboard.client"; `, "src/routes/soft-navigation/dashboard.client.tsx": js` "use client"; - + import { useState } from "react"; import { Link } from "react-router"; - + // Export the entire route as a client component export default function DashboardRoute({ loaderData }) { const [count, setCount] = useState(loaderData.count); - + return (

Dashboard

- + {/* Server data rendered in client component */}

Server count: {loaderData.count}

- + {/* Client interactive elements */}

Client count: {count}

- + - + Home
); @@ -599,11 +599,11 @@ implementations.forEach((implementation) => { "src/routes/request-context/home.tsx": js` import { testContext } from "../../config/request-context"; - + export function loader({ context }) { return { contextValue: context.get(testContext) }; } - + export default function HomeRoute({ loaderData }) { return (
@@ -615,16 +615,16 @@ implementations.forEach((implementation) => { "src/routes/resource-request-context/home.client.tsx": js` "use client"; - + import { useFetcher } from "react-router"; - + export function ResourceFetcher() { const fetcher = useFetcher(); - + const loadResource = () => { fetcher.submit({ hello: "world" }, { method: "post", action: "/resource-request-context/resource" }); }; - + return (