diff --git a/.agents/skills/react-router/SKILL.md b/.agents/skills/react-router/SKILL.md new file mode 100644 index 0000000000..949e3aeaee --- /dev/null +++ b/.agents/skills/react-router/SKILL.md @@ -0,0 +1,122 @@ +--- +name: react-router +description: Build applications with React Router in Framework, Data, Declarative, and unstable RSC modes. Use when configuring routes, route modules, loaders, actions, forms, fetchers, navigation, pending UI, SSR/SPA/pre-rendering, middleware, URL params/search params, or React Router upgrades. +license: MIT +--- + +# React Router + +React Router is mode-specific. Before changing an app, identify the mode, load the matching reference, then read the installed docs for the installed package version. + +## Identify the Mode + +Do not apply Framework/Data patterns to a Declarative app unless you are intentionally migrating modes. + +### Framework Mode + +Use Framework Mode guidance when you see: + +- `@react-router/dev` in dependencies +- `react-router.config.ts` +- `app/routes.ts` +- `app/entry.server.tsx` and/or `app/entry.client.tsx` files +- route modules under `app/routes/` +- route exports like `loader`, `action`, `clientLoader`, `clientAction`, `ErrorBoundary`, `meta`, `links`, or `headers` +- imports from `./+types/...` +- the React Router Vite plugin from `@react-router/dev/vite` + +Framework examples usually use the default `app/` directory, but check `react-router.config.ts` for a custom `appDirectory` before assuming exact paths. + +Then read `references/framework-mode.md`. + +### Data Mode + +Use Data Mode guidance when you see: + +- `createBrowserRouter`, `createHashRouter`, `createMemoryRouter`, or `createStaticRouter` +- `` +- route objects with properties like `path`, `children`, `loader`, `action`, `Component`, `ErrorBoundary`, or `lazy` +- data APIs without the Framework Vite plugin + +Then read `references/data-mode.md`. + +### Declarative Mode + +Use Declarative Mode guidance when you see: + +- ``, ``, or `` +- `` and `` JSX route configuration +- route components passed with `element={}` +- no data router, no route module convention, and no loaders/actions + +Then read `references/declarative-mode.md`. + +### RSC Framework and RSC Data Modes + +React Server Components support is unstable and exists in both Framework and Data variants. Use RSC guidance when you see: + +- `unstable_reactRouterRSC` +- `@vitejs/plugin-rsc` +- `unstable_RSCRouteConfig` +- RSC entry files such as `entry.rsc` +- `ServerComponent`, `ServerErrorBoundary`, `ServerLayout`, or `ServerHydrateFallback` +- React directives or boundary packages such as `"use client"`, `"server-only"`, or `"client-only"` + +For RSC Framework, read both `references/framework-mode.md` and `references/rsc.md`. +For RSC Data, read both `references/data-mode.md` and `references/rsc.md`. + +## Use Installed Docs as Source of Truth + +React Router ships markdown docs in the package so guidance can match the installed version: + +```txt +node_modules/react-router/docs/ +``` + +Key docs paths: + +```txt +node_modules/react-router/docs/index.md +node_modules/react-router/docs/start/ +node_modules/react-router/docs/how-to/ +node_modules/react-router/docs/explanation/ +node_modules/react-router/docs/upgrading/ +``` + +When this skill references `react-router/docs/...`, read the matching file under `node_modules/react-router/docs/`. If the installed version does not include local docs, use the repo `docs/` directory when working inside the React Router repository; in a consuming app, fall back to version-matched website docs. + +Most docs include a mode marker near the top: + +```txt +[MODES: framework, data, declarative] +``` + +Only apply a doc when its mode marker matches the app mode. If a task spans modes, prefer the section or file that matches the current app. + +RSC is documented primarily in: + +```txt +node_modules/react-router/docs/how-to/react-server-components.md +``` + +## Skill References + +Load the relevant reference after identifying the mode: + +| Reference | Use When | +| -------------------------------- | --------------------------------------------- | +| `references/framework-mode.md` | Framework Mode or RSC Framework base behavior | +| `references/data-mode.md` | Data Mode or RSC Data base behavior | +| `references/declarative-mode.md` | Declarative Mode | +| `references/rsc.md` | Any unstable RSC app | + +## Mode Migration Doc Index + +If the user explicitly asks to switch modes, read the target mode reference plus the migration-relevant docs: + +| Migration | Docs to read | +| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Declarative → Data | `react-router/docs/start/modes.md`, `react-router/docs/start/data/routing.md`, `react-router/docs/start/data/data-loading.md`, `react-router/docs/start/data/actions.md` | +| Declarative/Data → Framework | `react-router/docs/start/modes.md`, `react-router/docs/start/framework/routing.md`, `react-router/docs/start/framework/route-module.md`, `react-router/docs/how-to/route-module-type-safety.md` | +| Framework SPA/SSR/pre-render changes | `react-router/docs/start/framework/rendering.md`, `react-router/docs/how-to/spa.md`, `react-router/docs/how-to/pre-rendering.md`, `react-router/docs/start/framework/data-loading.md`, `react-router/docs/start/framework/actions.md` | +| Future flags/upgrades | `react-router/docs/upgrading/future.md` and relevant files under `react-router/docs/upgrading/` | diff --git a/.agents/skills/react-router/references/data-mode.md b/.agents/skills/react-router/references/data-mode.md new file mode 100644 index 0000000000..ea3480ccff --- /dev/null +++ b/.agents/skills/react-router/references/data-mode.md @@ -0,0 +1,165 @@ +# Data Mode + +Data Mode uses data routers such as `createBrowserRouter` and renders with ``. It gives an app route objects, loaders, actions, pending UI, fetchers, and SSR primitives without adopting the Framework Vite plugin or route-module file conventions. + +Use this reference after the main skill identifies a Data Mode app. + +## Read the Local Docs by Mode + +Start with: + +```txt +react-router/docs/start/modes.md +react-router/docs/start/data/index.md +``` + +Then use the Data docs under: + +```txt +react-router/docs/start/data/ +``` + +Those files cover installation, route objects, routing, data loading, actions, navigation, pending UI, and testing. For task-specific details, read relevant files in: + +```txt +react-router/docs/how-to/ +react-router/docs/explanation/ +``` + +Always check the `[MODES: data, ...]` marker in a doc before applying it. + +## Data Router Shape + +Typical setup: + +```tsx +import { createBrowserRouter, RouterProvider } from "react-router"; + +const router = createBrowserRouter([ + { + path: "/", + Component: Root, + loader: rootLoader, + children: [ + { index: true, Component: Home }, + { + path: "projects/:projectId", + Component: Project, + loader: projectLoader, + }, + ], + }, +]); + +root.render(); +``` + +Look for route object arrays and APIs such as: + +- `createBrowserRouter` +- `createHashRouter` +- `createMemoryRouter` +- `RouterProvider` +- `loader` +- `action` +- `Component` +- `ErrorBoundary` +- `lazy` +- `children` + +## Route Objects and Routing + +Before editing route configuration, read: + +```txt +react-router/docs/start/data/routing.md +react-router/docs/start/data/route-object.md +``` + +Rules: + +- Keep route objects outside render when possible. +- Use nested routes for shared layouts and data boundaries. +- Use index routes for default child content. +- Use dynamic segments and splats according to route-object docs. +- Prefer `Component`/`ErrorBoundary` route object properties in Data Mode examples unless the existing app uses `element` consistently. + +## Data and Mutations + +Before working on data loading or mutations, read: + +```txt +react-router/docs/start/data/data-loading.md +react-router/docs/start/data/actions.md +``` + +Rules: + +- Load route data with route `loader` functions. +- Mutate route data with route `action` functions. +- Prefer loaders/actions over route-level `useEffect` fetching. +- Use `request`, `params`, and returned/throwable Responses as described in the docs. +- Let React Router revalidate after actions unless there is a documented reason to customize revalidation. + +Common patterns: + +- Validation failure from an action: return `data({ errors, values }, { status: 400 })`, then render errors with `useActionData()` or `fetcher.data`. +- Missing record in a loader: throw `data("Not Found", { status: 404 })` and render the route `ErrorBoundary`. +- Search/filter data: parse `new URL(request.url).searchParams` in the loader so the URL is shareable and bookmarkable. + +## Forms, Fetchers, and Pending UI + +For forms and pending UI, read: + +```txt +react-router/docs/start/data/actions.md +react-router/docs/start/data/pending-ui.md +react-router/docs/how-to/fetchers.md +react-router/docs/explanation/form-vs-fetcher.md +``` + +Rules of thumb: + +- Search/filter form that updates the URL: `
`. +- Mutation that should change URL/history or redirect after completion: ``. +- Mutation that should keep the user on the same page: `useFetcher` / ``. +- Optimistic UI: derive from `fetcher.formData` or `navigation.formData`. + +## Navigation and URL State + +Before changing navigation or search params, read: + +```txt +react-router/docs/start/data/navigating.md +react-router/docs/how-to/search-params.md +react-router/docs/explanation/location.md +``` + +Rules: + +- Use ``/`` for user-initiated internal navigation. +- Use `redirect` in loaders/actions when navigation follows data loading or mutations. +- Use `useNavigate` for imperative client-side event navigation. +- Treat URL params as strings and validate/parse them. +- Preserve unrelated search params unless intentionally resetting them. + +## SSR in Data Mode + +Data Mode SSR is manual and lower-level than Framework Mode. Before implementing or changing SSR, read the Data Mode custom/SSR docs and match existing server abstractions. + +Start with: + +```txt +react-router/docs/start/data/custom.md +``` + +Look for APIs like `createStaticHandler`, `createStaticRouter`, `StaticRouterProvider`, and hydration data handling in the current app before changing anything. + +## RSC Data + +If this Data Mode app uses `unstable_RSCRouteConfig`, RSC route config, or low-level RSC server APIs, also read: + +```txt +references/rsc.md +react-router/docs/how-to/react-server-components.md +``` diff --git a/.agents/skills/react-router/references/declarative-mode.md b/.agents/skills/react-router/references/declarative-mode.md new file mode 100644 index 0000000000..982a3c4c01 --- /dev/null +++ b/.agents/skills/react-router/references/declarative-mode.md @@ -0,0 +1,123 @@ +# Declarative Mode + +Declarative Mode is React Router's simplest mode. It uses router components like `` and JSX routes with ``/``. It does not provide loaders, actions, fetchers, or data-router pending UI. + +Use this reference after the main skill identifies a Declarative Mode app. + +## Read the Local Docs by Mode + +Start with: + +```txt +react-router/docs/start/modes.md +react-router/docs/start/declarative/index.md +``` + +Then use the Declarative docs under: + +```txt +react-router/docs/start/declarative/ +``` + +Those files cover installation, routing, navigation, and URL values. For conceptual details, read relevant files in: + +```txt +react-router/docs/explanation/ +``` + +Always check the `[MODES: declarative, ...]` marker in a doc before applying it. + +## Declarative Router Shape + +Typical setup: + +```tsx +import { BrowserRouter, Routes, Route } from "react-router"; + +function App() { + return ( + + + } /> + } /> + }> + } /> + } /> + + + + ); +} +``` + +Look for APIs such as: + +- `` +- `` +- `` +- `` +- `` +- `element={}` +- `useRoutes` + +## Routing + +Before editing routes, read: + +```txt +react-router/docs/start/declarative/routing.md +``` + +Rules: + +- Use `` and `` for route configuration. +- Use nested routes with `` for shared layout. +- Use index routes for default child UI. +- Use route params and splats according to the declarative routing docs. +- Do not add route object loaders/actions to a Declarative router. + +## Navigation + +Before changing navigation, read: + +```txt +react-router/docs/start/declarative/navigating.md +``` + +Rules: + +- Use `` or `` for user-initiated internal navigation. +- Use `NavLink` when active styling matters. +- Use `useNavigate` for imperative navigation from event handlers or effects. +- Do not use plain `` for internal navigation unless intentionally forcing a full document navigation. + +## URL Values + +Before changing params, search params, or location state, read: + +```txt +react-router/docs/start/declarative/url-values.md +react-router/docs/explanation/location.md +``` + +Rules: + +- Use `useParams` for dynamic route params. +- Use `useSearchParams` for query string state. +- Use `useLocation` for the current location object and navigation state. +- Validate and parse URL params; they are strings and can be absent. +- Preserve unrelated search params unless intentionally resetting them. + +## Mode Boundary + +Declarative Mode does not have Data/Framework APIs such as: + +- `loader` +- `action` +- `` +- `useFetcher` +- `useNavigation` +- route module exports +- generated `./+types` route types + +If the user asks for route data loading, DB/API-backed data, CRUD, form mutations, validation returned from submissions, revalidation, pending UI, optimistic UI, or fetchers, recommend Data Mode or Framework Mode depending on how much structure they want. Ask before migrating unless they already requested it. diff --git a/.agents/skills/react-router/references/framework-mode.md b/.agents/skills/react-router/references/framework-mode.md new file mode 100644 index 0000000000..5c3e096a01 --- /dev/null +++ b/.agents/skills/react-router/references/framework-mode.md @@ -0,0 +1,213 @@ +# Framework Mode + +Framework Mode is React Router's full-stack mode. It uses the React Router Vite plugin, route config in `app/routes.ts`, route modules, generated route types, and rendering strategies such as SSR, SPA mode, and pre-rendering. + +Use this reference after the main skill identifies a Framework Mode app. + +## Read the Local Docs by Mode + +Start with: + +```txt +react-router/docs/start/modes.md +react-router/docs/start/framework/index.md +``` + +Then use the Framework docs under: + +```txt +react-router/docs/start/framework/ +``` + +Those files cover installation, routing, route modules, data loading, actions, navigation, pending UI, rendering, deploying, and testing. For task-specific details, read relevant files in: + +```txt +react-router/docs/how-to/ +react-router/docs/explanation/ +``` + +Always check the `[MODES: framework, ...]` marker in a doc before applying it. + +## Framework Shape + +Examples usually assume the default `appDirectory` of `app`. Check `react-router.config.ts` before assuming exact paths. + +Look for these files and conventions: + +```txt +react-router.config.ts +app/root.tsx +app/routes.ts +app/routes/**/*.tsx +route modules importing from ./+types/... +``` + +Typical route module: + +```tsx +import type { Route } from "./+types/product"; + +export async function loader({ params }: Route.LoaderArgs) { + return { product: await getProduct(params.productId) }; +} + +export default function Product({ loaderData }: Route.ComponentProps) { + return

{loaderData.product.name}

; +} +``` + +## Route Configuration + +Framework apps use `app/routes.ts`. Many apps use file-system routing via `flatRoutes()`, but manual route config is also supported. + +Before editing routes, read: + +```txt +react-router/docs/start/framework/routing.md +``` + +If the app uses file-route conventions, read: + +```txt +react-router/docs/how-to/file-route-conventions.md +``` + +## Route Modules + +Route modules are the main unit of Framework Mode. Before adding or changing route exports, read: + +```txt +react-router/docs/start/framework/route-module.md +``` + +Common exports include: + +| Export | Use | +| --------------------------------- | ------------------------------------------------------------------- | +| `default` | Route component rendered for the match | +| `loader` | Server data loading for SSR/pre-rendering/server data requests | +| `clientLoader` | Browser-only data loading or supplementing server loader data | +| `action` | Server mutation called by ``, `useSubmit`, or fetchers | +| `clientAction` | Browser-only mutation or client-side wrapper around a server action | +| `ErrorBoundary` | UI for errors thrown by this route's loaders/actions/component | +| `HydrateFallback` | Initial fallback while client loader hydration runs | +| `links` / `meta` | Route document links and metadata | +| `handle` | Arbitrary route metadata consumed via `useMatches` | +| `shouldRevalidate` | Overrides default loader revalidation behavior | +| `middleware` / `clientMiddleware` | Server/client request pipeline hooks when enabled | + +Use generated `Route.*` types from `./+types/` for route module args and props. + +## Layout and Root Route Rules + +- `app/root.tsx` is the root route and should contain global document/app shell concerns. +- Put global providers, app-wide nav, app-wide footer, scripts/meta/links, and document structure in `root.tsx` when appropriate. +- Use nested routes/layout routes for section-specific layouts. +- Do not flatten routes that should share UI or data boundaries. + +Useful docs: + +```txt +react-router/docs/explanation/special-files.md +react-router/docs/start/framework/routing.md +``` + +## Data and Mutations + +Before working on route data: + +```txt +react-router/docs/start/framework/data-loading.md +react-router/docs/start/framework/actions.md +``` + +Framework rules: + +- Load route data with `loader` or `clientLoader`. +- Mutate route data with `action` or `clientAction`. +- Prefer route loaders/actions over ad hoc `useEffect` fetching for route data. +- Use `data()`/Responses and redirects according to the docs. +- Let React Router revalidate after actions unless the docs point you to `shouldRevalidate`. +- In SSR/server data routes, keep Node-only/database code in server-only modules and call it from `loader`/`action`, not from browser-rendered component code. + +Common patterns: + +- Validation failure from an action: return `data({ errors, values }, { status: 400 })`, then render errors from `Route.ComponentProps["actionData"]` or `fetcher.data`. +- Missing record in a loader: throw `data("Not Found", { status: 404 })` and render the route `ErrorBoundary`. +- Search/filter data: parse the route request URL/search params in the loader so the URL is shareable and bookmarkable. + +## Forms, Fetchers, and Pending UI + +For forms and pending UI, read: + +```txt +react-router/docs/start/framework/actions.md +react-router/docs/start/framework/pending-ui.md +react-router/docs/how-to/fetchers.md +react-router/docs/explanation/form-vs-fetcher.md +``` + +Rules of thumb: + +- Search/filter form that updates the URL: ``. +- Mutation that should change URL/history or redirect after completion: ``. +- Mutation that should keep the user on the same page: `useFetcher` / ``. +- Optimistic UI: derive from `fetcher.formData` or `navigation.formData`. + +## Type Safety + +Before changing generated route types or typed URL behavior, read: + +```txt +react-router/docs/how-to/route-module-type-safety.md +react-router/docs/explanation/type-safety.md +``` + +Rules: + +- Import types from `./+types/`. +- Use `Route.LoaderArgs`, `Route.ActionArgs`, `Route.ComponentProps`, etc. +- Use type-only imports where appropriate. +- Do not edit generated `.react-router/types` files. + +## Metadata + +Before changing `meta`, read: + +```txt +react-router/docs/how-to/meta.md +react-router/docs/start/framework/route-module.md +``` + +Important: `meta` receives `loaderData`; do not use deprecated `data` args. + +## Rendering Strategy + +Framework Mode can be SSR, SPA, pre-rendered, or mixed depending on config and route behavior. Before changing rendering behavior, read: + +```txt +react-router/docs/start/framework/rendering.md +react-router/docs/how-to/spa.md +react-router/docs/how-to/pre-rendering.md +react-router/docs/explanation/hydration.md +``` + +## Middleware, Sessions, and Auth + +Before implementing middleware or auth/session flows, read: + +```txt +react-router/docs/how-to/middleware.md +react-router/docs/explanation/sessions-and-cookies.md +``` + +Middleware and context APIs are version/config sensitive. Check the installed React Router version and the app's `react-router.config.ts` before implementing. + +## RSC Framework + +If this Framework app uses `unstable_reactRouterRSC` or `@vitejs/plugin-rsc`, also read: + +```txt +references/rsc.md +react-router/docs/how-to/react-server-components.md +``` diff --git a/.agents/skills/react-router/references/rsc.md b/.agents/skills/react-router/references/rsc.md new file mode 100644 index 0000000000..b940821dac --- /dev/null +++ b/.agents/skills/react-router/references/rsc.md @@ -0,0 +1,90 @@ +# React Server Components (RSC) + +React Router's RSC support is unstable and exists in two variants: + +- **RSC Framework Mode**: Framework Mode with the unstable RSC Vite plugin. +- **RSC Data Mode**: lower-level RSC runtime APIs and manual bundler/server integration. + +Use this reference in addition to `framework-mode.md` or `data-mode.md` after the main skill identifies an RSC app. + +## Read the Local RSC Docs + +Start with: + +```txt +react-router/docs/how-to/react-server-components.md +``` + +Then read the relevant base mode docs: + +```txt +react-router/docs/start/framework/ +react-router/docs/start/data/ +``` + +RSC docs may describe differences from non-RSC mode rather than repeating every Framework/Data concept, so keep both layers in mind. + +## Detect RSC Framework Mode + +Look for: + +- `unstable_reactRouterRSC` imported from `@react-router/dev/vite` +- `@vitejs/plugin-rsc` +- `vite.config.ts` with `plugins: [reactRouterRSC(), rsc()]` +- Framework route modules plus RSC route exports +- RSC entry files such as `entry.rsc` + +RSC Framework Mode uses a different Vite plugin from non-RSC Framework Mode. Do not swap it for the regular `reactRouter()` plugin. + +## Detect RSC Data Mode + +Look for: + +- `unstable_RSCRouteConfig` +- route config passed to lower-level RSC APIs +- APIs such as `unstable_matchRSCServerRequest`, `unstable_routeRSCServerRequest`, `unstable_RSCHydratedRouter`, or `unstable_RSCStaticRouter` +- custom bundler/server setup around RSC + +RSC Data Mode is more manual than RSC Framework Mode. Match the app's bundler and server abstractions before changing routes or entries. + +## RSC Route Module Differences + +In RSC Framework Mode, many normal Framework Mode concepts still apply, but routes can use server component exports. + +Important route-module concepts from the RSC docs include: + +- `ServerComponent` instead of the usual client `default` component +- `ServerErrorBoundary` paired with `ErrorBoundary` +- `ServerLayout` paired with `Layout` +- `ServerHydrateFallback` paired with `HydrateFallback` +- server-rendered React elements returned from loaders/actions + +A route module cannot export both the normal client component and its server component counterpart for the same role. Read the RSC docs before adding these exports. + +## Client/Server Boundaries + +RSC code must respect React's client/server split: + +- Use `"use client"` for components that need hooks, browser APIs, or event handlers. +- Use server-only modules for server data access and secrets. +- In RSC Framework Mode, prefer the `server-only` and `client-only` boundary imports described in the docs. +- Do not assume `.server`/`.client` file naming works the same way in RSC Framework Mode; read the RSC docs before relying on those conventions. + +## Data Loading in RSC + +RSC changes where data can be loaded: + +- Server Components can fetch data directly on the server. +- Loaders/actions may still exist and can have RSC-specific behavior. +- Client components still need client-safe data and cannot directly access server-only modules. + +When choosing between a server component fetch, a loader, and a client loader/action, follow the RSC docs and match existing app patterns. + +## Stability + +RSC APIs are explicitly unstable. Before implementing or refactoring RSC code: + +- Check the installed React Router version. +- Check the installed `@vitejs/plugin-rsc` version. +- Read the app's existing RSC entry/config files. +- Prefer minimal changes that match current patterns. diff --git a/CHANGELOG.md b/CHANGELOG.md index b556c29a17..dd39d23bfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -182,6 +182,12 @@ We manage release notes in this file instead of the paginated Github Releases Pa Date: 2026-06-16 +### What's Changed + +#### CSRF Check Logic Fix + +We made a bug fix in our underlying CSRF checks in this release that may be a "breaking bug fix" for some users deployed behind a reverse proxy. The CSRF check now checks directly against the `host` in the `request` url provided, instead of looking directly at HTTP headers which is an adapter concern. If your adapter is not setting the expected host in the request URL, you may need to add the new internal host to your `allowedActionOrigins` config. This is most likely to occur in `@react-router/serve` apps or `@react-router/express` apps without the `trust proxy` setting enabled. We recommend testing this against application mutation requests as part of your upgrade. + ### Minor Changes - `@react-router/architect` - Add a `useRequestContextDomainName` option to `createRequestHandler` to derive request URL hosts from the API Gateway request context ([#15185](https://github.com/remix-run/react-router/pull/15185)) diff --git a/docs/community/api-development-strategy.md b/docs/community/api-development-strategy.md index bfb5cd64ad..43acc3d09f 100644 --- a/docs/community/api-development-strategy.md +++ b/docs/community/api-development-strategy.md @@ -15,7 +15,7 @@ When an API changes in a breaking way, it is introduced in a future flag. This a - Without enabling the future flag, nothing changes about your app - Enabling the flag changes the behavior for that feature -All current future flags are documented in the [Future Flags Guide](../upgrading/future) to help you stay up-to-date. +All current future flags are documented in the [Future Changes Guide](../upgrading/future) to help you stay up-to-date. ## Unstable Flags @@ -30,7 +30,7 @@ Unstable flags are not recommended for production: When you opt-in to an unstable flag you are becoming a contributor to the project, rather than a user. We appreciate your help, but please be aware of the new role! -Because unstable flags are experimental and not guaranteed to stick around, we ship them in SemVer patch releases because they're not new _stable_/_documented_ APIs. When an unstable flag stabilizes into a Future Flag, that will be released in a SemVer minor release and will be properly documented and added to the [Future Flags Guide](../upgrading/future). +Because unstable flags are experimental and not guaranteed to stick around, we ship them in SemVer patch releases because they're not new _stable_/_documented_ APIs. When an unstable flag stabilizes into a Future Flag, that will be released in a SemVer minor release and will be properly documented and added to the [Future Changes Guide](../upgrading/future). To learn about current unstable flags, keep an eye on the [CHANGELOG](../start/changelog). diff --git a/docs/how-to/status.md b/docs/how-to/status.md index 906f4007cc..00d2e4ec03 100644 --- a/docs/how-to/status.md +++ b/docs/how-to/status.md @@ -54,7 +54,7 @@ export async function loader({ params }: Route.ActionArgs) { let project = await fakeDb.getProject(params.id); if (!project) { // throw to ErrorBoundary - throw data(null, { status: 404 }); + throw data("Not Found", { status: 404 }); } return project; } diff --git a/docs/upgrading/future.md b/docs/upgrading/future.md index ee4053030d..a3e45d916e 100644 --- a/docs/upgrading/future.md +++ b/docs/upgrading/future.md @@ -1,17 +1,34 @@ --- -title: Future Flags +title: Future Changes order: 1 --- -# Future Flags and Deprecations +# Future Changes -This guide walks you through the process of adopting future flags in your React Router app. By following this strategy, you will be able to upgrade to the next major version of React Router with minimal changes. To read more about future flags see [API Development Strategy][api-development-strategy]. +We try our best to keep major version upgrades simple and boring through the use of opt-in APIs and [Future Flags][api-development-strategy]. Future flags are used to gate breaking changes that don't otherwise have a good call-site opt-in strategy. By adopting all opt-in APIs and future flags, you should be able to upgrade to the next major version of React Router with minimal changes. 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. +## Minimum Versions + +[MODES: framework, data, declarative] + +
+
+ +React Router v8 will require the following minimum versions. You can prepare for the upgrade by updating them while still on v7: + +- `node@22.22+` +- `react@19.2.7+`/`react-dom@19.2.7+` + +Framework mode will also require: + +- `vite@7+` (requires `future.v8_viteEnvironmentApi`) + - also make sure any custom Vite plugins or config are compatible with Vite 7. + ## 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. +Before adopting any future flags or call-site opt-in changes, you should update to the latest minor version of v7.x to make sure you have access to the latest flags. You may see a number of deprecation warnings as you upgrade, which we'll cover below. 👉 Update to latest v7 @@ -19,7 +36,9 @@ First update to the latest minor version of v7.x to have the latest future flags npm install react-router@7 @react-router/{dev,node,etc.}@7 ``` -## `future.v8_middleware` +## Future Flags + +### `future.v8_middleware` [MODES: framework, data] @@ -47,7 +66,7 @@ export default { In Data mode: ```ts -import { createBrowserRouter } from "react-router/dom"; +import { createBrowserRouter } from "react-router"; const router = createBrowserRouter(routes, { future: { @@ -63,7 +82,7 @@ If you're using the `context` parameter in `loader` and `action` functions, you - In Framework mode, if you're using `react-router-serve`, you should not need to make any updates. Otherwise, this only applies if you have a custom server with a `getLoadContext` function. Please see the docs on the middleware [`getLoadContext` changes](../how-to/middleware#changes-to-getloadcontextapploadcontext) and the instructions to [migrate to the new API](../how-to/middleware#migration-from-apploadcontext). - In Data mode, add the `Future` module augmentation described in the [middleware docs](../how-to/middleware#1-typescript-augment-future-for-loaderaction-context) so `context` is typed correctly. -## `future.v8_splitRouteModules` +### `future.v8_splitRouteModules` [MODES: framework] @@ -92,7 +111,7 @@ export default { No code changes are required. This is an optimization feature that works automatically once enabled. -## `future.v8_viteEnvironmentApi` +### `future.v8_viteEnvironmentApi` [MODES: framework] @@ -150,7 +169,7 @@ import { defineConfig } from "vite"; See the [`node-custom-server` template][node-custom-server-template] for a complete example. -## `future.v8_passThroughRequests` +### `future.v8_passThroughRequests` [MODES: framework] @@ -213,7 +232,7 @@ export async function loader({ } ``` -## `future.v8_trailingSlashAwareDataRequests` +### `future.v8_trailingSlashAwareDataRequests` [MODES: framework] @@ -266,11 +285,201 @@ export default { If you have custom app, CDN, cache, or rewrite logic that matches `.data` request URLs, update it to handle the new trailing-slash-aware `/_.data` format. +## Other Planned Breaking Changes + +The changes in this section are not controlled by future flags, but you can update your code in v7 to be ready for v8. + +### `meta` `data` Argument + +[MODES: framework] + +
+
+ +**Background** + +The `data` fields passed to route module `meta` functions are deprecated and will be removed in React Router v8. Use `loaderData` instead on `MetaArgs` and each item in `MetaArgs.matches`. + +👉 **Update your Code** + +Replace `data` with `loaderData` in your `meta` functions: + +```diff +export function meta({ +- data, ++ loaderData, + matches, +}: Route.MetaArgs) { + return [ + { +- title: data.title, ++ title: loaderData.title, + }, + ]; +} +``` + +If you read data from parent matches, update those references too: + +```diff +export function meta({ matches }: Route.MetaArgs) { + let rootMatch = matches.find((match) => match.id === "root"); +- let rootData = rootMatch?.data; ++ let rootData = rootMatch?.loaderData; + + return [{ title: rootData?.siteTitle }]; +} +``` + +### `react-router-dom` + +[MODES: framework, data, declarative] + +
+
+ +**Background** + +React Router v8 will remove the `react-router-dom` re-export package. In v8, you should import DOM-specific APIs from `react-router/dom` and everything else from `react-router`. + +👉 **Update your Code** + +Uninstall `react-router-dom`: + +```sh +npm uninstall react-router-dom +``` + +Replace `react-router-dom` imports with `react-router` imports: + +```diff +-import { Link, useLocation } from "react-router-dom"; ++import { Link, useLocation } from "react-router"; +``` + +For DOM-specific APIs, import from `react-router/dom`: + +```diff +-import { RouterProvider } from "react-router-dom"; ++import { RouterProvider } from "react-router/dom"; +``` + +### Cloudflare Vite Plugin + +[MODES: framework] + +
+
+ +**Background** + +React Router v8 will remove the React Router Cloudflare dev proxy. Cloudflare projects should use [`@cloudflare/vite-plugin`][cloudflare-vite-plugin] instead. + +👉 **Update your Code** + +Replace `cloudflareDevProxy` with `cloudflare`: + +```diff filename=vite.config.ts +import { reactRouter } from "@react-router/dev/vite"; +-import { cloudflareDevProxy } from "@react-router/dev/vite/cloudflare"; ++import { cloudflare } from "@cloudflare/vite-plugin"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [ +- cloudflareDevProxy(), ++ cloudflare(), + reactRouter(), + ], +}); +``` + +### `@react-router/architect` `useRequestContextDomainName` + +[MODES: framework] + +
+
+ +**Background** + +The `@react-router/architect` adapter currently uses `X-Forwarded-Host` when creating the `request`, falling back to the `Host` header. In React Router v8, the adapter will use `event.requestContext.domainName` by default, falling back to the `Host` header. + +👉 **Update your Code** + +Opt in to the v8 behavior now by passing `useRequestContextDomainName: true`: + +```ts +import { createRequestHandler } from "@react-router/architect"; +import * as build from "./build/server"; + +export const handler = createRequestHandler({ + build, + useRequestContextDomainName: true, +}); +``` + +This option will be removed in v8 once the `event.requestContext.domainName` behavior is the default. + ## Unstable Future Flags (Optional) -We document some [unstable] flags here as a reference for folks contributing to the project via beta testing, but they are not generally recommended for production use and may having breaking changes patch/minor releases - adopt with caution! +We document some [unstable] flags here as a reference for folks contributing to the project via beta testing, but they are not generally recommended for production use and may have breaking changes in patch or minor releases - adopt with caution! + +### `future.unstable_optimizeDeps` + +[MODES: framework] + +
+
+ +**Background** + +This flag lets React Router provide Vite's dependency optimizer with the client entry file and route module files. This can improve dependency optimization in development, but the behavior is still experimental. + +👉 **Enable the Flag** + +```ts filename=react-router.config.ts +import type { Config } from "@react-router/dev/config"; + +export default { + future: { + unstable_optimizeDeps: true, + }, +} satisfies Config; +``` + +**Update your Code** + +No code changes are required. If you run into dependency optimization issues after enabling this flag, remove the flag and restart the dev server. + +### `future.unstable_previewServerPrerendering` + +[MODES: framework] + +
+
+ +**Background** + +This flag switches prerendering to use Vite's preview-server request flow instead of the current build-time prerendering path so that it works in non-Node environments such as `workerd`. Enabling this flag also enables `future.v8_viteEnvironmentApi`, so you should review the `future.v8_viteEnvironmentApi` guidance above before adopting it. + +This ends up only changing the underlying prerender implementation but is not expected to cause any breaking changes. Because it is not expected to break, you do not _have_ to adopt this flag prior to v8 and therefore it wasn't ever converted to a `v8_` flag. + +👉 **Enable the Flag** + +```ts filename=react-router.config.ts +import type { Config } from "@react-router/dev/config"; + +export default { + future: { + unstable_previewServerPrerendering: true, + }, +} satisfies Config; +``` + +**Update your Code** -_No current unstable flags to document_ +No code changes are required unless your app has a custom Vite configuration that is affected by `future.v8_viteEnvironmentApi`. [api-development-strategy]: ../community/api-development-strategy [unstable]: ../community/api-development-strategy#unstable-flags @@ -278,3 +487,4 @@ _No current unstable flags to document_ [Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response [vite-environment]: https://vite.dev/guide/api-environment [node-custom-server-template]: https://github.com/remix-run/react-router-templates/blob/7c617a435510bc3add3a5395c07bc65328b65e9e/node-custom-server/vite.config.ts +[cloudflare-vite-plugin]: https://developers.cloudflare.com/workers/vite-plugin/ diff --git a/docs/upgrading/remix.md b/docs/upgrading/remix.md index 667d89895c..fc8ae9f419 100644 --- a/docs/upgrading/remix.md +++ b/docs/upgrading/remix.md @@ -1,9 +1,9 @@ --- -title: Upgrading from Remix +title: Upgrading from Remix v2 order: 3 --- -# Upgrading from Remix +# Upgrading from Remix v2