UNPKG

@react-router/dev

Version:

Dev tools and CLI for React Router

1,047 lines (743 loc) 136 kB
# `@react-router/dev` ## 7.10.1 ### Patch Changes - Import ESM package `pkg-types` with a dynamic `import()` to fix issues on Node 20.18 ([#14624](https://github.com/remix-run/react-router/pull/14624)) - Update `valibot` dependency to `^1.2.0` to address [GHSA-vqpr-j7v3-hqw9](https://github.com/advisories/GHSA-vqpr-j7v3-hqw9) ([#14608](https://github.com/remix-run/react-router/pull/14608)) - Updated dependencies: - `react-router@7.10.1` - `@react-router/node@7.10.1` - `@react-router/serve@7.10.1` ## 7.10.0 ### Minor Changes - Stabilize `future.v8_splitRouteModules`, replacing `future.unstable_splitRouteModules` ([#14595](https://github.com/remix-run/react-router/pull/14595)) - ⚠️ This is a breaking change if you have begun using `future.unstable_splitRouteModules`. Please update your `react-router.config.ts`. - Stabilize `future.v8_viteEnvironmentApi`, replacing `future.unstable_viteEnvironmentApi` ([#14595](https://github.com/remix-run/react-router/pull/14595)) - ⚠️ This is a breaking change if you have begun using `future.unstable_viteEnvironmentApi`. Please update your `react-router.config.ts`. ### Patch Changes - Load environment variables before evaluating `routes.ts` ([#14446](https://github.com/remix-run/react-router/pull/14446)) For example, you can now compute your routes based on [`VITE_`-prefixed environment variables](https://vite.dev/guide/env-and-mode#env-variables): ```txt # .env VITE_ENV_ROUTE=my-route ``` ```ts // app/routes.ts import { type RouteConfig, route } from "@react-router/dev/routes"; const routes: RouteConfig = []; if (import.meta.env.VITE_ENV_ROUTE === "my-route") { routes.push(route("my-route", "routes/my-route.tsx")); } export default routes; ``` - Updated dependencies: - `react-router@7.10.0` - `@react-router/node@7.10.0` - `@react-router/serve@7.10.0` ## 7.9.6 ### Patch Changes - Use a dynamic `import()` to load ESM-only `p-map` dependency to avoid issues on Node 20.18 and below ([#14492](https://github.com/remix-run/react-router/pull/14492)) - Short circuit `HEAD` document requests before calling `renderToPipeableStream` in the default `entry.server.tsx` to more closely align with the [spec](https://httpwg.org/specs/rfc9110.html#HEAD) ([#14488](https://github.com/remix-run/react-router/pull/14488)) - Updated dependencies: - `react-router@7.9.6` - `@react-router/node@7.9.6` - `@react-router/serve@7.9.6` ## 7.9.5 ### Patch Changes - Introduce a `prerender.unstable_concurrency` option, to support running the prerendering concurrently, potentially speeding up the build. ([#14380](https://github.com/remix-run/react-router/pull/14380)) - Move RSCHydratedRouter and utils to `/dom` export. ([#14457](https://github.com/remix-run/react-router/pull/14457)) - Ensure route navigation doesn't remove CSS `link` elements used by dynamic imports ([#14463](https://github.com/remix-run/react-router/pull/14463)) - Typegen: only register route module types for routes within the app directory ([#14439](https://github.com/remix-run/react-router/pull/14439)) - Updated dependencies: - `react-router@7.9.5` - `@react-router/node@7.9.5` - `@react-router/serve@7.9.5` ## 7.9.4 ### Patch Changes - Update `valibot` dependency to `^1.1.0` ([#14379](https://github.com/remix-run/react-router/pull/14379)) - New (unstable) `useRoute` hook for accessing data from specific routes ([#14407](https://github.com/remix-run/react-router/pull/14407)) For example, let's say you have an `admin` route somewhere in your app and you want any child routes of `admin` to all have access to the `loaderData` and `actionData` from `admin.` ```tsx // app/routes/admin.tsx import { Outlet } from "react-router"; export const loader = () => ({ message: "Hello, loader!" }); export const action = () => ({ count: 1 }); export default function Component() { return ( <div> {/* ... */} <Outlet /> {/* ... */} </div> ); } ``` You might even want to create a reusable widget that all of the routes nested under `admin` could use: ```tsx import { unstable_useRoute as useRoute } from "react-router"; export function AdminWidget() { // How to get `message` and `count` from `admin` route? } ``` In framework mode, `useRoute` knows all your app's routes and gives you TS errors when invalid route IDs are passed in: ```tsx export function AdminWidget() { const admin = useRoute("routes/dmin"); // ^^^^^^^^^^^ } ``` `useRoute` returns `undefined` if the route is not part of the current page: ```tsx export function AdminWidget() { const admin = useRoute("routes/admin"); if (!admin) { throw new Error(`AdminWidget used outside of "routes/admin"`); } } ``` Note: the `root` route is the exception since it is guaranteed to be part of the current page. As a result, `useRoute` never returns `undefined` for `root`. `loaderData` and `actionData` are marked as optional since they could be accessed before the `action` is triggered or after the `loader` threw an error: ```tsx export function AdminWidget() { const admin = useRoute("routes/admin"); if (!admin) { throw new Error(`AdminWidget used outside of "routes/admin"`); } const { loaderData, actionData } = admin; console.log(loaderData); // ^? { message: string } | undefined console.log(actionData); // ^? { count: number } | undefined } ``` If instead of a specific route, you wanted access to the _current_ route's `loaderData` and `actionData`, you can call `useRoute` without arguments: ```tsx export function AdminWidget() { const currentRoute = useRoute(); currentRoute.loaderData; currentRoute.actionData; } ``` This usage is equivalent to calling `useLoaderData` and `useActionData`, but consolidates all route data access into one hook: `useRoute`. Note: when calling `useRoute()` (without a route ID), TS has no way to know which route is the current route. As a result, `loaderData` and `actionData` are typed as `unknown`. If you want more type-safety, you can either narrow the type yourself with something like `zod` or you can refactor your app to pass down typed props to your `AdminWidget`: ```tsx export function AdminWidget({ message, count, }: { message: string; count: number; }) { /* ... */ } ``` - Updated dependencies: - `react-router@7.9.4` - `@react-router/node@7.9.4` - `@react-router/serve@7.9.4` ## 7.9.3 ### Patch Changes - Updated dependencies: - `react-router@7.9.3` - `@react-router/node@7.9.3` - `@react-router/serve@7.9.3` ## 7.9.2 ### Patch Changes - Fix preset future flags being ignored during config resolution ([#14369](https://github.com/remix-run/react-router/pull/14369)) Fixes a bug where future flags defined by presets were completely ignored. The config resolution was incorrectly reading from `reactRouterUserConfig.future` instead of the merged `userAndPresetConfigs.future`, causing all preset-defined future flags to be lost. This fix ensures presets can properly enable experimental features as intended by the preset system design. - Add unstable support for RSC Framework Mode ([#14336](https://github.com/remix-run/react-router/pull/14336)) - Switch internal vite plugin Response logic to use `@remix-run/node-fetch-server` ([#13927](https://github.com/remix-run/react-router/pull/13927)) - Updated dependencies: - `react-router@7.9.2` - `@react-router/serve@7.9.2` - `@react-router/node@7.9.2` ## 7.9.1 ### Patch Changes - Fix internal `Future` interface naming from `middleware` -> `v8_middleware` ([#14327](https://github.com/remix-run/react-router/pull/14327)) - Updated dependencies: - `react-router@7.9.1` - `@react-router/node@7.9.1` - `@react-router/serve@7.9.1` ## 7.9.0 ### Minor Changes - Stabilize middleware and context APIs. ([#14215](https://github.com/remix-run/react-router/pull/14215)) We have removed the `unstable_` prefix from the following APIs and they are now considered stable and ready for production use: - [`RouterContextProvider`](https://reactrouter.com/api/utils/RouterContextProvider) - [`createContext`](https://reactrouter.com/api/utils/createContext) - `createBrowserRouter` [`getContext`](https://reactrouter.com/api/data-routers/createBrowserRouter#optsgetcontext) option - `<HydratedRouter>` [`getContext`](https://reactrouter.com/api/framework-routers/HydratedRouter#getcontext) prop Please see the [Middleware Docs](https://reactrouter.com/how-to/middleware), the [Middleware RFC](https://github.com/remix-run/remix/discussions/7642), and the [Client-side Context RFC](https://github.com/remix-run/react-router/discussions/9856) for more information. ### Patch Changes - Updated dependencies: - `react-router@7.9.0` - `@react-router/node@7.9.0` - `@react-router/serve@7.9.0` ## 7.8.2 ### Patch Changes - fix: memory leak in default entry.server ([#14200](https://github.com/remix-run/react-router/pull/14200)) - Updated dependencies: - `react-router@7.8.2` - `@react-router/node@7.8.2` - `@react-router/serve@7.8.2` ## 7.8.1 ### Patch Changes - Update generated `Route.MetaArgs` type so `loaderData` is only potentially undefined when an `ErrorBoundary` export is present ([#14173](https://github.com/remix-run/react-router/pull/14173)) - Updated dependencies: - `react-router@7.8.1` - `@react-router/node@7.8.1` - `@react-router/serve@7.8.1` ## 7.8.0 ### Patch Changes - Fix rename without mkdir in Vite plugin ([#14105](https://github.com/remix-run/react-router/pull/14105)) - Updated dependencies: - `react-router@7.8.0` - `@react-router/node@7.8.0` - `@react-router/serve@7.8.0` ## 7.7.1 ### Patch Changes - Update to Prettier v3 for formatting when running `react-router reveal --no-typescript` ([#14049](https://github.com/remix-run/react-router/pull/14049)) - Updated dependencies: - `react-router@7.7.1` - `@react-router/node@7.7.1` - `@react-router/serve@7.7.1` ## 7.7.0 ### Patch Changes - Update `vite-node` to `^3.2.2` to support Vite 7 ([#13781](https://github.com/remix-run/react-router/pull/13781)) - Properly handle `https` protocol in dev mode ([#13746](https://github.com/remix-run/react-router/pull/13746)) - Fix missing styles when Vite's `build.cssCodeSplit` option is disabled ([#13943](https://github.com/remix-run/react-router/pull/13943)) - Allow `.mts` and `.mjs` extensions for route config file ([#13931](https://github.com/remix-run/react-router/pull/13931)) - Fix prerender file locations when `cwd` differs from project root ([#13824](https://github.com/remix-run/react-router/pull/13824)) - Improve chunk error logging when a chunk cannot be found during the build ([#13799](https://github.com/remix-run/react-router/pull/13799)) - Fix incorrectly configured `externalConditions` which had enabled `module` condition for externals and broke builds with certain packages, like Emotion. ([#13871](https://github.com/remix-run/react-router/pull/13871)) - Updated dependencies: - `react-router@7.7.0` - `@react-router/node@7.7.0` - `@react-router/serve@7.7.0` ## 7.6.3 ### Patch Changes - Add Vite 7 support ([#13748](https://github.com/remix-run/react-router/pull/13748)) - Skip `package.json` resolution checks when a custom `entry.server.(j|t)sx` file is provided. ([#13744](https://github.com/remix-run/react-router/pull/13744)) - Add validation for a route's id not being 'root' ([#13792](https://github.com/remix-run/react-router/pull/13792)) - Updated dependencies: - `@react-router/node@7.6.3` - `react-router@7.6.3` - `@react-router/serve@7.6.3` ## 7.6.2 ### Patch Changes - Avoid additional `with-props` chunk in Framework Mode by moving route module component prop logic from the Vite plugin to `react-router` ([#13650](https://github.com/remix-run/react-router/pull/13650)) - When `future.unstable_viteEnvironmentApi` is enabled and an absolute Vite `base` has been configured, ensure critical CSS is handled correctly during development ([#13598](https://github.com/remix-run/react-router/pull/13598)) - Update `vite-node` ([#13673](https://github.com/remix-run/react-router/pull/13673)) - Fix typegen for non-{.js,.jsx,.ts,.tsx} routes like .mdx ([#12453](https://github.com/remix-run/react-router/pull/12453)) - Fix href types for optional dynamic params ([#13725](https://github.com/remix-run/react-router/pull/13725)) 7.6.1 introduced fixes for `href` when using optional static segments, but those fixes caused regressions with how optional dynamic params worked in 7.6.0: ```ts // 7.6.0 href("/users/:id?"); // ✅ href("/users/:id?", { id: 1 }); // ✅ // 7.6.1 href("/users/:id?"); // ❌ href("/users/:id?", { id: 1 }); // ❌ ``` Now, optional static segments are expanded into different paths for `href`, but optional dynamic params are not. This way `href` can unambiguously refer to an exact URL path, all while keeping the number of path options to a minimum. ```ts // 7.6.2 // path: /users/:id?/edit? href(" // ^ suggestions when cursor is here: // // /users/:id? // /users/:id?/edit ``` Additionally, you can pass `params` from component props without needing to narrow them manually: ```ts declare const params: { id?: number }; // 7.6.0 href("/users/:id?", params); // 7.6.1 href("/users/:id?", params); // ❌ "id" in params ? href("/users/:id", params) : href("/users"); // works... but is annoying // 7.6.2 href("/users/:id?", params); // restores behavior of 7.6.0 ``` - Updated dependencies: - `react-router@7.6.2` - `@react-router/node@7.6.2` - `@react-router/serve@7.6.2` ## 7.6.1 ### Patch Changes - Prevent typegen with route files are outside the app directory ([#12996](https://github.com/remix-run/react-router/pull/12996)) - Fix typegen when same route is used at multiple paths ([#13574](https://github.com/remix-run/react-router/pull/13574)) For example, `routes/route.tsx` is used at 4 different paths here: ```ts import { type RouteConfig, route } from "@react-router/dev/routes"; export default [ route("base/:base", "routes/base.tsx", [ route("home/:home", "routes/route.tsx", { id: "home" }), route("changelog/:changelog", "routes/route.tsx", { id: "changelog" }), route("splat/*", "routes/route.tsx", { id: "splat" }), ]), route("other/:other", "routes/route.tsx", { id: "other" }), ] satisfies RouteConfig; ``` Previously, typegen would arbitrarily pick one of these paths to be the "winner" and generate types for the route module based on that path. Now, typegen creates unions as necessary for alternate paths for the same route file. - Add additional logging to `build` command output when cleaning assets from server build ([#13547](https://github.com/remix-run/react-router/pull/13547)) - Better types for `params` ([#13543](https://github.com/remix-run/react-router/pull/13543)) For example: ```ts // routes.ts import { type RouteConfig, route } from "@react-router/dev/routes"; export default [ route("parent/:p", "routes/parent.tsx", [ route("layout/:l", "routes/layout.tsx", [ route("child1/:c1a/:c1b", "routes/child1.tsx"), route("child2/:c2a/:c2b", "routes/child2.tsx"), ]), ]), ] satisfies RouteConfig; ``` Previously, `params` for the `routes/layout.tsx` route were calculated as `{ p: string, l: string }`. This incorrectly ignores params that could come from child routes. If visiting `/parent/1/layout/2/child1/3/4`, the actual params passed to `routes/layout.tsx` will have a type of `{ p: string, l: string, c1a: string, c1b: string }`. Now, `params` are aware of child routes and autocompletion will include child params as optionals: ```ts params.| // ^ cursor is here and you ask for autocompletion // p: string // l: string // c1a?: string // c1b?: string // c2a?: string // c2b?: string ``` You can also narrow the types for `params` as it is implemented as a normalized union of params for each page that includes `routes/layout.tsx`: ```ts if (typeof params.c1a === 'string') { params.| // ^ cursor is here and you ask for autocompletion // p: string // l: string // c1a: string // c1b: string } ``` *** UNSTABLE: renamed internal `react-router/route-module` export to `react-router/internal` UNSTABLE: removed `Info` export from generated `+types/*` files - \[UNSTABLE] Normalize dirent entry path across node versions when generating SRI manifest ([#13591](https://github.com/remix-run/react-router/pull/13591)) - Don't clean assets from server build when `build.ssrEmitAssets` has been enabled in Vite config ([#13547](https://github.com/remix-run/react-router/pull/13547)) - Fix `href` for optional segments ([#13595](https://github.com/remix-run/react-router/pull/13595)) Type generation now expands paths with optionals into their corresponding non-optional paths. For example, the path `/user/:id?` gets expanded into `/user` and `/user/:id` to more closely model visitable URLs. `href` then uses these expanded (non-optional) paths to construct type-safe paths for your app: ```ts // original: /user/:id? // expanded: /user & /user/:id href("/user"); // ✅ href("/user/:id", { id: 1 }); // ✅ ``` This becomes even more important for static optional paths where there wasn't a good way to indicate whether the optional should be included in the resulting path: ```ts // original: /products/:id/detail? // before href("/products/:id/detail?"); // ❌ How can we tell `href` to include or omit `detail?` segment with a complex API? // now // expanded: /products/:id & /products/:id/detail href("/product/:id"); // ✅ href("/product/:id/detail"); // ✅ ``` - Updated dependencies: - `react-router@7.6.1` - `@react-router/node@7.6.1` - `@react-router/serve@7.6.1` ## 7.6.0 ### Minor Changes - Added a new `react-router.config.ts` `routeDiscovery` option to configure Lazy Route Discovery behavior. ([#13451](https://github.com/remix-run/react-router/pull/13451)) - By default, Lazy Route Discovery is enabled and makes manifest requests to the `/__manifest` path: - `routeDiscovery: { mode: "lazy", manifestPath: "/__manifest" }` - You can modify the manifest path used: - `routeDiscovery: { mode: "lazy", manifestPath: "/custom-manifest" }` - Or you can disable this feature entirely and include all routes in the manifest on initial document load: - `routeDiscovery: { mode: "initial" }` - Automatic types for future flags ([#13506](https://github.com/remix-run/react-router/pull/13506)) Some future flags alter the way types should work in React Router. Previously, you had to remember to manually opt-in to the new types. For example, for `unstable_middleware`: ```ts // react-router.config.ts // Step 1: Enable middleware export default { future: { unstable_middleware: true, }, }; // Step 2: Enable middleware types declare module "react-router" { interface Future { unstable_middleware: true; // 👈 Enable middleware types } } ``` It was up to you to keep the runtime future flags synced with the types for those future flags. This was confusing and error-prone. Now, React Router will automatically enable types for future flags. That means you only need to specify the runtime future flag: ```ts // react-router.config.ts // Step 1: Enable middleware export default { future: { unstable_middleware: true, }, }; // No step 2! That's it! ``` Behind the scenes, React Router will generate the corresponding `declare module` into `.react-router/types`. Currently this is done in `.react-router/types/+register.ts` but this is an implementation detail that may change in the future. ### Patch Changes - Support project root directories without a `package.json` if it exists in a parent directory ([#13472](https://github.com/remix-run/react-router/pull/13472)) - When providing a custom Vite config path via the CLI `--config`/`-c` flag, default the project root directory to the directory containing the Vite config when not explicitly provided ([#13472](https://github.com/remix-run/react-router/pull/13472)) - In a `routes.ts` context, ensure the `--mode` flag is respected for `import.meta.env.MODE` ([#13485](https://github.com/remix-run/react-router/pull/13485)) Previously, `import.meta.env.MODE` within a `routes.ts` context was always `"development"` for the `dev` and `typegen --watch` commands, but otherwise resolved to `"production"`. These defaults are still in place, but if a `--mode` flag is provided, this will now take precedence. - Ensure consistent project root directory resolution logic in CLI commands ([#13472](https://github.com/remix-run/react-router/pull/13472)) - When executing `react-router.config.ts` and `routes.ts` with `vite-node`, ensure that PostCSS config files are ignored ([#13489](https://github.com/remix-run/react-router/pull/13489)) - When extracting critical CSS during development, ensure it's loaded from the client environment to avoid issues with plugins that handle the SSR environment differently ([#13503](https://github.com/remix-run/react-router/pull/13503)) - When `future.unstable_viteEnvironmentApi` is enabled, ensure that `build.assetsDir` in Vite config is respected when `environments.client.build.assetsDir` is not configured ([#13491](https://github.com/remix-run/react-router/pull/13491)) - Fix "Status message is not supported by HTTP/2" error during dev when using HTTPS ([#13460](https://github.com/remix-run/react-router/pull/13460)) - Update config when `react-router.config.ts` is created or deleted during development. ([#12319](https://github.com/remix-run/react-router/pull/12319)) - Skip unnecessary `routes.ts` evaluation before Vite build is started ([#13513](https://github.com/remix-run/react-router/pull/13513)) - Fix `TS2300: Duplicate identifier` errors caused by generated types ([#13499](https://github.com/remix-run/react-router/pull/13499)) Previously, routes that had the same full path would cause duplicate entries in the generated types for `href` (`.react-router/types/+register.ts`), causing type checking errors. - Updated dependencies: - `react-router@7.6.0` - `@react-router/node@7.6.0` - `@react-router/serve@7.6.0` ## 7.5.3 ### Patch Changes - Updated dependencies: - `react-router@7.5.3` - `@react-router/node@7.5.3` - `@react-router/serve@7.5.3` ## 7.5.2 ### Patch Changes - Adjust approach for Prerendering/SPA Mode via headers ([#13453](https://github.com/remix-run/react-router/pull/13453)) - Updated dependencies: - `react-router@7.5.2` - `@react-router/node@7.5.2` - `@react-router/serve@7.5.2` ## 7.5.1 ### Patch Changes - Fix prerendering when a loader returns a redirect ([#13365](https://github.com/remix-run/react-router/pull/13365)) - Updated dependencies: - `react-router@7.5.1` - `@react-router/node@7.5.1` - `@react-router/serve@7.5.1` ## 7.5.0 ### Patch Changes - Introduce `unstable_subResourceIntegrity` future flag that enables generation of an importmap with integrity for the scripts that will be loaded by the browser. ([#13163](https://github.com/remix-run/react-router/pull/13163)) - Update optional Wrangler peer dependency range to support Wrangler v4 ([#13258](https://github.com/remix-run/react-router/pull/13258)) - When `future.unstable_viteEnvironmentApi` is enabled, ensure critical CSS in development works when using a custom Vite `base` has been configured ([#13305](https://github.com/remix-run/react-router/pull/13305)) - Reinstate dependency optimization in the child compiler to fix `depsOptimizer is required in dev mode` errors when using `vite-plugin-cloudflare` and importing Node.js builtins ([#13317](https://github.com/remix-run/react-router/pull/13317)) - Updated dependencies: - `react-router@7.5.0` - `@react-router/node@7.5.0` - `@react-router/serve@7.5.0` ## 7.4.1 ### Patch Changes - Fix path in prerender error messages ([#13257](https://github.com/remix-run/react-router/pull/13257)) - Fix typegen for virtual modules when `moduleDetection` is set to `force` ([#13267](https://github.com/remix-run/react-router/pull/13267)) - When both `future.unstable_middleware` and `future.unstable_splitRouteModules` are enabled, split `unstable_clientMiddleware` route exports into separate chunks when possible ([#13210](https://github.com/remix-run/react-router/pull/13210)) - Improve performance of `future.unstable_middleware` by ensuring that route modules are only blocking during the middleware phase when the `unstable_clientMiddleware` has been defined ([#13210](https://github.com/remix-run/react-router/pull/13210)) - Updated dependencies: - `react-router@7.4.1` - `@react-router/node@7.4.1` - `@react-router/serve@7.4.1` ## 7.4.0 ### Minor Changes - Generate types for `virtual:react-router/server-build` module ([#13152](https://github.com/remix-run/react-router/pull/13152)) ### Patch Changes - When `future.unstable_splitRouteModules` is set to `"enforce"`, allow both splittable and unsplittable root route exports since it's always in a single chunk. ([#13238](https://github.com/remix-run/react-router/pull/13238)) - When `future.unstable_viteEnvironmentApi` is enabled, allow plugins that override the default SSR environment (such as `@cloudflare/vite-plugin`) to be placed before or after the React Router plugin. ([#13183](https://github.com/remix-run/react-router/pull/13183)) - Fix conflicts with other Vite plugins that use the `configureServer` and/or `configurePreviewServer` hooks ([#13184](https://github.com/remix-run/react-router/pull/13184)) - Updated dependencies: - `react-router@7.4.0` - `@react-router/node@7.4.0` - `@react-router/serve@7.4.0` ## 7.3.0 ### Patch Changes - Fix support for custom client `build.rollupOptions.output.entryFileNames` ([#13098](https://github.com/remix-run/react-router/pull/13098)) - Fix usage of `prerender` option when `serverBundles` option has been configured or provided by a preset, e.g. `vercelPreset` from `@vercel/react-router` ([#13082](https://github.com/remix-run/react-router/pull/13082)) - Fix support for custom `build.assetsDir` ([#13077](https://github.com/remix-run/react-router/pull/13077)) - Remove unused dependencies ([#13134](https://github.com/remix-run/react-router/pull/13134)) - Stub all routes except root in "SPA Mode" server builds to avoid issues when route modules or their dependencies import non-SSR-friendly modules ([#13023](https://github.com/remix-run/react-router/pull/13023)) - Fix errors with `future.unstable_viteEnvironmentApi` when the `ssr` environment has been configured by another plugin to be a custom `Vite.DevEnvironment` rather than the default `Vite.RunnableDevEnvironment` ([#13008](https://github.com/remix-run/react-router/pull/13008)) - Remove unused Vite file system watcher ([#13133](https://github.com/remix-run/react-router/pull/13133)) - Fix support for custom SSR build input when `serverBundles` option has been configured ([#13107](https://github.com/remix-run/react-router/pull/13107)) Note that for consumers using the `future.unstable_viteEnvironmentApi` and `serverBundles` options together, hyphens are no longer supported in server bundle IDs since they also need to be valid Vite environment names. - Fix dev server when using HTTPS by stripping HTTP/2 pseudo headers from dev server requests ([#12830](https://github.com/remix-run/react-router/pull/12830)) - Lazy load Cloudflare platform proxy on first dev server request when using the `cloudflareDevProxy` Vite plugin to avoid creating unnecessary workerd processes ([#13016](https://github.com/remix-run/react-router/pull/13016)) - When `future.unstable_viteEnvironmentApi` is enabled and the `ssr` environment has `optimizeDeps.noDiscovery` disabled, define `optimizeDeps.entries` and `optimizeDeps.include` ([#13007](https://github.com/remix-run/react-router/pull/13007)) - Fix duplicated entries in typegen for layout routes and their corresponding index route ([#13140](https://github.com/remix-run/react-router/pull/13140)) - Updated dependencies: - `react-router@7.3.0` - `@react-router/node@7.3.0` - `@react-router/serve@7.3.0` ## 7.2.0 ### Minor Changes - Generate a "SPA fallback" HTML file for scenarios where applications are prerendering the `/` route with `ssr:false` ([#12948](https://github.com/remix-run/react-router/pull/12948)) - If you specify `ssr:false` without a `prerender` config, this is considered "SPA Mode" and the generated `index.html` file will only render down to the root route and will be able to hydrate for any valid application path - If you specify `ssr:false` with a `prerender` config but _do not_ include the `/` path (i.e., `prerender: ['/blog/post']`), then we still generate a "SPA Mode" `index.html` file that can hydrate for any path in the application - However, previously if you specified `ssr:false` and included the `/` path in your `prerender` config, we would prerender the `/` route into `index.html` as a non-SPA page - The generated HTML would include the root index route which prevented hydration for any other paths - With this change, we now generate a "SPA Mode" file in `__spa-fallback.html` that will allow you to hydrate for any non-prerendered paths - You can serve this file from your static file server for any paths that would otherwise 404 if you only want to pre-render _some_ routes in your `ssr:false` app and serve the others as a SPA - `npx sirv-cli build/client --single __spa-fallback.html` - Allow a `loader` in the root route in SPA mode because it can be called/server-rendered at build time ([#12948](https://github.com/remix-run/react-router/pull/12948)) - `Route.HydrateFallbackProps` now also receives `loaderData` - This will be defined so long as the `HydrateFallback` is rendering while _children_ routes are loading - This will be `undefined` if the `HydrateFallback` is rendering because the route has it's own hydrating `clientLoader` - In SPA mode, this will allow you to render loader root data into the SPA `index.html` - New type-safe `href` utility that guarantees links point to actual paths in your app ([#13012](https://github.com/remix-run/react-router/pull/13012)) ```tsx import { href } from "react-router"; export default function Component() { const link = href("/blog/:slug", { slug: "my-first-post" }); return ( <main> <Link to={href("/products/:id", { id: "asdf" })} /> <NavLink to={href("/:lang?/about", { lang: "en" })} /> </main> ); } ``` ### Patch Changes - Handle custom `envDir` in Vite config ([#12969](https://github.com/remix-run/react-router/pull/12969)) - Fix typegen for repeated params ([#13012](https://github.com/remix-run/react-router/pull/13012)) In React Router, path parameters are keyed by their name. So for a path pattern like `/a/:id/b/:id?/c/:id`, the last `:id` will set the value for `id` in `useParams` and the `params` prop. For example, `/a/1/b/2/c/3` will result in the value `{ id: 3 }` at runtime. Previously, generated types for params incorrectly modeled repeated params with an array. So `/a/1/b/2/c/3` generated a type like `{ id: [1,2,3] }`. To be consistent with runtime behavior, the generated types now correctly model the "last one wins" semantics of path parameters. So `/a/1/b/2/c/3` now generates a type like `{ id: 3 }`. - Fix CLI parsing to allow argumentless `npx react-router` usage ([#12925](https://github.com/remix-run/react-router/pull/12925)) - Fix `ArgError: unknown or unexpected option: --version` when running `react-router --version` ([#13012](https://github.com/remix-run/react-router/pull/13012)) - Skip action-only resource routes when using `prerender:true` ([#13004](https://github.com/remix-run/react-router/pull/13004)) - Enhance invalid export detection when using `ssr:false` ([#12948](https://github.com/remix-run/react-router/pull/12948)) - `headers`/`action` are prohibited in all routes with `ssr:false` because there will be no runtime server on which to run them - `loader` functions are more nuanced and depend on whether a given route is prerendered - When using `ssr:false` without a `prerender` config, only the `root` route can have a `loader` - This is "SPA mode" which generates a single `index.html` file with the root route `HydrateFallback` so it is capable of hydrating for any path in your application - therefore we can only call a root route `loader` at build time - When using `ssr:false` with a `prerender` config, you can export a `loader` from routes matched by one of the `prerender` paths because those routes will be server rendered at build time - Exporting a `loader` from a route that is never matched by a `prerender` path will throw a build time error because there will be no runtime server to ever run the loader - Limit prerendered resource route `.data` files to only the target route ([#13004](https://github.com/remix-run/react-router/pull/13004)) - Add unstable support for splitting route modules in framework mode via `future.unstable_splitRouteModules` ([#11871](https://github.com/remix-run/react-router/pull/11871)) - Fix prerendering of binary files ([#13039](https://github.com/remix-run/react-router/pull/13039)) - Add `future.unstable_viteEnvironmentApi` flag to enable experimental Vite Environment API support ([#12936](https://github.com/remix-run/react-router/pull/12936)) - Disable Lazy Route Discovery for all `ssr:false` apps and not just "SPA Mode" because there is no runtime server to serve the search-param-configured `__manifest` requests ([#12894](https://github.com/remix-run/react-router/pull/12894)) - We previously only disabled this for "SPA Mode" which is `ssr:false` and no `prerender` config but we realized it should apply to all `ssr:false` apps, including those prerendering multiple pages - In those `prerender` scenarios we would prerender the `/__manifest` file assuming the static file server would serve it but that makes some unneccesary assumptions about the static file server behaviors - Updated dependencies: - `react-router@7.2.0` - `@react-router/node@7.2.0` - `@react-router/serve@7.2.0` ## 7.1.5 ### Patch Changes - Updated dependencies: - `react-router@7.1.5` - `@react-router/node@7.1.5` - `@react-router/serve@7.1.5` ## 7.1.4 ### Patch Changes - Properly resolve Windows file paths to scan for Vite's dependency optimization when using the `unstable_optimizeDeps` future flag. ([#12637](https://github.com/remix-run/react-router/pull/12637)) - Fix prerendering when using a custom server - previously we ended up trying to import the users custom server when we actually want to import the virtual server build module ([#12759](https://github.com/remix-run/react-router/pull/12759)) - Updated dependencies: - `react-router@7.1.4` - `@react-router/node@7.1.4` - `@react-router/serve@7.1.4` ## 7.1.3 ### Patch Changes - Fix `reveal` and `routes` CLI commands ([#12745](https://github.com/remix-run/react-router/pull/12745)) - Updated dependencies: - `react-router@7.1.3` - `@react-router/node@7.1.3` - `@react-router/serve@7.1.3` ## 7.1.2 ### Patch Changes - Fix default external conditions in Vite v6. This fixes resolution issues with certain npm packages. ([#12644](https://github.com/remix-run/react-router/pull/12644)) - Fix mismatch in prerendering html/data files when path is missing a leading slash ([#12684](https://github.com/remix-run/react-router/pull/12684)) - Use `module-sync` server condition when enabled in the runtime. This fixes React context mismatches (e.g. `useHref() may be used only in the context of a <Router> component.`) during development on Node 22.10.0+ when using libraries that have a peer dependency on React Router. ([#12729](https://github.com/remix-run/react-router/pull/12729)) - Fix react-refresh source maps ([#12686](https://github.com/remix-run/react-router/pull/12686)) - Updated dependencies: - `react-router@7.1.2` - `@react-router/node@7.1.2` - `@react-router/serve@7.1.2` ## 7.1.1 ### Patch Changes - Fix for a crash when optional args are passed to the CLI ([`5b1ca202f`](https://github.com/remix-run/react-router/commit/5b1ca202f77ef342db0109c6b791d33188077cd0)) - Updated dependencies: - `react-router@7.1.1` - `@react-router/node@7.1.1` - `@react-router/serve@7.1.1` ## 7.1.0 ### Minor Changes - Add support for Vite v6 ([#12469](https://github.com/remix-run/react-router/pull/12469)) ### Patch Changes - Properly initialize `NODE_ENV` if not already set for compatibility with React 19 ([#12578](https://github.com/remix-run/react-router/pull/12578)) - Remove the leftover/unused `abortDelay` prop from `ServerRouter` and update the default `entry.server.tsx` to use the new `streamTimeout` value for Single Fetch ([#12478](https://github.com/remix-run/react-router/pull/12478)) - The `abortDelay` functionality was removed in v7 as it was coupled to the `defer` implementation from Remix v2, but this removal of this prop was missed - If you were still using this prop in your `entry.server` file, it's likely your app is not aborting streams as you would expect and you will need to adopt the new [`streamTimeout`](https://reactrouter.com/explanation/special-files#streamtimeout) value introduced with Single Fetch - Updated dependencies: - `react-router@7.1.0` - `@react-router/node@7.1.0` - `@react-router/serve@7.1.0` ## 7.0.2 ### Patch Changes - Support `moduleResolution` `Node16` and `NodeNext` ([#12440](https://github.com/remix-run/react-router/pull/12440)) - Generate wide `matches` and `params` types for current route and child routes ([#12397](https://github.com/remix-run/react-router/pull/12397)) At runtime, `matches` includes child route matches and `params` include child route path parameters. But previously, we only generated types for parent routes in `matches`; for `params`, we only considered the parent routes and the current route. To align our generated types more closely to the runtime behavior, we now generate more permissive, wider types when accessing child route information. - Updated dependencies: - `react-router@7.0.2` - `@react-router/node@7.0.2` - `@react-router/serve@7.0.2` ## 7.0.1 ### Patch Changes - Pass route error to ErrorBoundary as a prop ([#12338](https://github.com/remix-run/react-router/pull/12338)) - Ensure typegen file watcher is cleaned up when Vite dev server restarts ([#12331](https://github.com/remix-run/react-router/pull/12331)) - Updated dependencies: - `react-router@7.0.1` - `@react-router/node@7.0.1` - `@react-router/serve@7.0.1` ## 7.0.0 ### Major Changes - For Remix consumers migrating to React Router, the `vitePlugin` and `cloudflareDevProxyVitePlugin` exports have been renamed and moved. ([#11904](https://github.com/remix-run/react-router/pull/11904)) ```diff -import { - vitePlugin as remix, - cloudflareDevProxyVitePlugin, -} from "@remix/dev"; +import { reactRouter } from "@react-router/dev/vite"; +import { cloudflareDevProxy } from "@react-router/dev/vite/cloudflare"; ``` - Remove single fetch future flag. ([#11522](https://github.com/remix-run/react-router/pull/11522)) - update minimum node version to 18 ([#11690](https://github.com/remix-run/react-router/pull/11690)) - Add `exports` field to all packages ([#11675](https://github.com/remix-run/react-router/pull/11675)) - node package no longer re-exports from react-router ([#11702](https://github.com/remix-run/react-router/pull/11702)) - For Remix consumers migrating to React Router who used the Vite plugin's `buildEnd` hook, the resolved `reactRouterConfig` object no longer contains a `publicPath` property since this belongs to Vite, not React Router. ([#11575](https://github.com/remix-run/react-router/pull/11575)) - For Remix consumers migrating to React Router, the Vite plugin's `manifest` option has been removed. ([#11573](https://github.com/remix-run/react-router/pull/11573)) The `manifest` option been superseded by the more powerful `buildEnd` hook since it's passed the `buildManifest` argument. You can still write the build manifest to disk if needed, but you'll most likely find it more convenient to write any logic depending on the build manifest within the `buildEnd` hook itself. If you were using the `manifest` option, you can replace it with a `buildEnd` hook that writes the manifest to disk like this: ```ts // react-router.config.ts import type { Config } from "@react-router/dev/config"; import { writeFile } from "node:fs/promises"; export default { async buildEnd({ buildManifest }) { await writeFile( "build/manifest.json", JSON.stringify(buildManifest, null, 2), "utf-8", ); }, } satisfies Config; ``` - Consolidate types previously duplicated across `@remix-run/router`, `@remix-run/server-runtime`, and `@remix-run/react` now that they all live in `react-router` ([#12177](https://github.com/remix-run/react-router/pull/12177)) - Examples: `LoaderFunction`, `LoaderFunctionArgs`, `ActionFunction`, `ActionFunctionArgs`, `DataFunctionArgs`, `RouteManifest`, `LinksFunction`, `Route`, `EntryRoute` - The `RouteManifest` type used by the "remix" code is now slightly stricter because it is using the former `@remix-run/router` `RouteManifest` - `Record<string, Route> -> Record<string, Route | undefined>` - Removed `AppData` type in favor of inlining `unknown` in the few locations it was used - Removed `ServerRuntimeMeta*` types in favor of the `Meta*` types they were duplicated from - Update default `isbot` version to v5 and drop support for `isbot@3` ([#11770](https://github.com/remix-run/react-router/pull/11770)) - If you have `isbot@4` or `isbot@5` in your `package.json`: - You do not need to make any changes - If you have `isbot@3` in your `package.json` and you have your own `entry.server.tsx` file in your repo - You do not need to make any changes - You can upgrade to `isbot@5` independent of the React Router v7 upgrade - If you have `isbot@3` in your `package.json` and you do not have your own `entry.server.tsx` file in your repo - You are using the internal default entry provided by React Router v7 and you will need to upgrade to `isbot@5` in your `package.json` - Drop support for Node 18, update minimum Node vestion to 20 ([#12171](https://github.com/remix-run/react-router/pull/12171)) - Remove `installGlobals()` as this should no longer be necessary - For Remix consumers migrating to React Router, Vite manifests (i.e. `.vite/manifest.json`) are now written within each build subdirectory, e.g. `build/client/.vite/manifest.json` and `build/server/.vite/manifest.json` instead of `build/.vite/client-manifest.json` and `build/.vite/server-manifest.json`. This means that the build output is now much closer to what you'd expect from a typical Vite project. ([#11573](https://github.com/remix-run/react-router/pull/11573)) Originally the Remix Vite plugin moved all Vite manifests to a root-level `build/.vite` directory to avoid accidentally serving them in production, particularly from the client build. This was later improved with additional logic that deleted these Vite manifest files at the end of the build process unless Vite's `build.manifest` had been enabled within the app's Vite config. This greatly reduced the risk of accidentally serving the Vite manifests in production since they're only present when explicitly asked for. As a result, we can now assume that consumers will know that they need to manage these additional files themselves, and React Router can safely generate a more standard Vite build output. ### Minor Changes - Params, loader data, and action data as props for route component exports ([#11961](https://github.com/remix-run/react-router/pull/11961)) ```tsx export default function Component({ params, loaderData, actionData }) {} export function HydrateFallback({ params }) {} export function ErrorBoundary({ params, loaderData, actionData }) {} ``` - Remove internal entry.server.spa.tsx implementation ([#11681](https://github.com/remix-run/react-router/pull/11681)) - Add `prefix` route config helper to `@react-router/dev/routes` ([#12094](https://github.com/remix-run/react-router/pull/12094)) - ### Typesafety improvements ([#12019](https://github.com/remix-run/react-router/pull/12019)) React Router now generates types for each of your route modules. You can access those types by importing them from `./+types.<route filename without extension>`. For example: ```ts // app/routes/product.tsx import type * as Route from "./+types.product"; export function loader({ params }: Route.LoaderArgs) {} export default function Component({ loaderData }: Route.ComponentProps) {} ``` This initial implementation targets type inference for: - `Params` : Path parameters from your routing config in `routes.ts` including file-based routing - `LoaderData` : Loader data from `loader` and/or `clientLoader` within your route module - `ActionData` : Action data from `action` and/or `clientAction` within your route module In the future, we plan to add types for the rest of the route module exports: `meta`, `links`, `headers`, `shouldRevalidate`, etc. We also plan to generate types for typesafe `Link`s: ```tsx <Link to="/products/:id" params={{ id: 1 }} /> // ^^^^^^^^^^^^^ ^^^^^^^^^ // typesafe `to` and `params` based on the available routes in your app ``` Check out our docs for more: - [_Explanations > Type Safety_](https://reactrouter.com/dev/guides/explanation/type-safety) - [_How-To > Setting up type safety_](https://reactrouter.com/dev/guides/how-to/setting-up-type-safety) ### Patch Changes - Enable prerendering for resource routes ([#12200](https://github.com/remix-run/react-router/pull/12200)) - chore: warn instead of error for min node version in CLI ([#12270](https://github.com/remix-run/react-router/pull/12270)) - chore: re-enable development warnings through a `development` exports condition. ([#12269](https://github.com/remix-run/react-router/pull/12269)) - include root "react-dom" module for optimization ([#12060](https://github.com/remix-run/react-router/pull/12060)) - resolve config directory relative to flat output file structure ([#12187](https://github.com/remix-run/react-router/pull/12187)) - if we are in SAP mode, always render the `index.html` for hydration ([#12268](https://github.com/remix-run/react-router/pull/12268)) - fix(react-router): (v7) fix static prerender of non-ascii characters ([#12161](https://github.com/remix-run/react-router/pull/12161)) - Updated dependencies: - `react-router@7.0.0` - `@react-router/serve@7.0.0` - `@react-router/node@7.0.0` ## 2.9.0 ### Minor Changes - New `future.unstable_singleFetch` flag ([#8773](https://github.com/remix-run/remix/pull/8773)) - Naked objects returned from loaders/actions are no longer automatically converted to JSON responses. They'll be streamed as-is via `turbo-stream` so `Date`'s will become `Date` through `useLoaderData()` - You can return naked objects with `Promise`'s without needing to use `defer()` - including nested `Promise`'s - If you need to return a custom status code or custom response headers, you can still use the `defer` utility - `<RemixServer abortDelay>` is no longer used. Instead, you should `export const streamTimeout` from `entry.server.tsx` and the remix server runtime will use that as the delay to abort the streamed response - If you export your own streamTimeout, you should decouple that from aborting the react `renderToPipeableStream`. You should always ensure that react is aborted _afer_ the stream is aborted so that abort rejections can be flushed down - Actions no longer automatically revalidate on 4xx/5xx responses (via RR `future.unstable_skipActionErrorRevalidation` flag) - you can return a 2xx to opt-into revalidation or use `shouldRevalidate` ### Patch Changes - Improve `getDependenciesToBundle` resolution in monorepos ([#8848](https://github.com/remix-run/remix/pull/8848)) - Fix SPA mode when single fetch is enabled by using streaming entry.server ([#9063](https://github.com/remix-run/remix/pull/9063)) - Vite: added sourcemap support for transformed routes ([#8970](https://github.com/remix-run/remix/pull/8970)) - Update links printed to the console by the Remix CLI/Dev Server to point to updated docs locations ([#9176](https://github.com/remix-run/remix/pull/9176)) - Updated dependencies: - `@remix-run/node@2.9.0` - `@remix-run/server-runtime@2.9.0` ## 2.8.1 ### Patch Changes - Support reading from Vite config when running `remix reveal` and `remix routes` CLI commands ([#8916](https://github.com/remix-run/remix/pull/8916)) - Add Vite commands to Remix CLI `--help` output ([#8939](https://github.com/remix-run/remix/pull/8939)) - Vite: Fix support for `build.sourcemap` option in Vite config ([#8965](https://github.com/remix-run/remix/pull/8965)) - Clean up redundant client route query strings on route JavaScript files in production builds ([#8969](https://github.com/remix-run/remix/pull/8969)) - Vite: Fix error when using Vite's `server.fs.allow` option without a client entry file ([#8966](https://github.com/remix-run/remix/pull/8966)) - Updated dependencies: - `@remix-run/node@2.8.1` - `@remix-run/server-runtime@2.8.1` ## 2.8.0 ### Minor Changes - Pass resolved `viteConfig` to Remix Vite plugin's `buildEnd` hook ([#8885](https://github.com/r