Skip to content

Conversation

@renovate
Copy link
Contributor

@renovate renovate bot commented Feb 4, 2024

This PR contains the following updates:

Package Change Age Confidence
history 4.10.1 -> 5.3.0 age confidence
react-router (source) 5.3.4 -> 7.9.5 age confidence
react-router-dom (source) 5.3.4 -> 7.9.5 age confidence

Release Notes

remix-run/history (history)

v5.3.0

Compare Source

This release provides support for native ESM consumption of all exports.

v5.2.0

Compare Source

🐛 Bug fixes

  • Fixed a few type declarations and deprecated the following types:
    • State (now set to unknown which will require consumer type narrowing)
    • PartialPath (use Partial<Path> instead)
    • PartialLocation (use Partial<Location> instead)
  • Fixed a regression related to the createPath return value (#​813)

✨ Features

  • We now use statically analyzable CJS exports. This enables named imports in Node ESM scripts (See the commit).

Full Changelog: remix-run/history@v5.1.0...v5.2.0

v5.1.0

Compare Source

Because the prior 5.0.2 release removed the State type parameter from Location, this was technically a breaking change. To correct for this, I'm bumping this as a minor release. It won't affect runtime code, but it may affect your development experience and tests if you were using that parameter.

The State type export is also restored, so you shouldn't have issues with installing React Router v6.

Oh, by the way, did you hear we released React Router v6?

Full Changelog: remix-run/history@v5.0.3...v5.1.0

v5.0.3

Compare Source

Fixed parsePath adding incorrectly adding search

v5.0.2

Compare Source

Just a couple fixes:

  • Fixed search params persisting on redirects
  • Changed the location.state type to any and removed the generic on Location

Full Changelog: remix-run/history@v5.0.1...v5.0.2

v5.0.1

Compare Source

This patch release contains a tiny TypeScript update to use the built-in Partial utility for PartialPath and PartialLocation. We always love it when we can ship just a little less code!

🙏 Credits

Thanks to @​liuhanqu, @​hanquliu, @​chaance and @​mjackson for your contributions!

v5.0.0

Compare Source

Today we are very pleased to announce the stable release of history version 5!

Overview

This version includes many enhancements and fixes a few important issues with the library.

New Features
  • Hash history now has support for location.state
  • Better history.block API, with support for retrying transitions
  • Full TypeScript declarations and IntelliSense docs
  • Adds development and production builds for <script type=module> users
  • Both browser and hash history have support for iframes (custom window objects)
  • About 50% smaller than v4 (and no dependencies)
Bugfixes
  • Fixed some long-standing encoding issues with location.pathname
  • Removed unfixable warnings about pushing the same path in hash history
  • Renamed browser global to HistoryLibrary so it doesn't conflict with window.History
Breaking Changes
  • Removed support for browsers that do not support the HTML5 history API (no pushState)
  • Removed relative pathname support in hash history and memory history
  • Removed getUserConfirmation, keyLength, and hashType APIs

Usage

Please refer to our installation guide for instructions about how to install the library.

There is also a getting started guide as well as a complete API reference in the docs folder.

We are very excited about this release, especially because it will serve as the foundation for the upcoming release of React Router version 6.

Thank you for your support. Enjoy! 😀

remix-run/react-router (react-router)

v7.9.5

Compare Source

Patch Changes
  • Move RSCHydratedRouter and utils to /dom export. (#​14457)

  • useRoute: return type-safe handle (#​14462)

    For example:

    // app/routes/admin.tsx
    const handle = { hello: "world" };
    // app/routes/some-other-route.tsx
    export default function Component() {
      const admin = useRoute("routes/admin");
      if (!admin) throw new Error("Not nested within 'routes/admin'");
      console.log(admin.handle);
      //                ^? { hello: string }
    }
  • Ensure action handlers run for routes with middleware even if no loader is present (#​14443)

  • Add unstable_instrumentations API to allow users to add observablity to their apps by instrumenting route loaders, actions, middlewares, lazy, as well as server-side request handlers and client side navigations/fetches (#​14412)

    • Framework Mode:
      • entry.server.tsx: export const unstable_instrumentations = [...]
      • entry.client.tsx: <HydratedRouter unstable_instrumentations={[...]} />
    • Data Mode
      • createBrowserRouter(routes, { unstable_instrumentations: [...] })

    This also adds a new unstable_pattern parameter to loaders/actions/middleware which contains the un-interpolated route pattern (i.e., /blog/:slug) which is useful for aggregating performance metrics by route

v7.9.4

Compare Source

Patch Changes
  • handle external redirects in from server actions (#​14400)

  • New (unstable) useRoute hook for accessing data from specific routes (#​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.

    // 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:

    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:

    export function AdminWidget() {
      const admin = useRoute("routes/dmin");
      //                      ^^^^^^^^^^^
    }

    useRoute returns undefined if the route is not part of the current page:

    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:

    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:

    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:

    export function AdminWidget({
      message,
      count,
    }: {
      message: string;
      count: number;
    }) {
      /* ... */
    }

v7.9.3

Compare Source

Patch Changes
  • Do not try to use turbo-stream to decode CDN errors that never reached the server (#​14385)

    • We used to do this but lost this check with the adoption of single fetch
  • Fix Data Mode regression causing a 404 during initial load in when middleware exists without any loader functions (#​14393)

v7.9.2

Compare Source

Patch Changes
    • Update client-side router to run client middleware on initial load even if no loaders exist (#​14348)
    • Update createRoutesStub to run route middleware
      • You will need to set the <RoutesStub future={{ v8_middleware: true }} /> flag to enable the proper context type
  • Update Lazy Route Discovery manifest requests to use a singular comma-separated paths query param instead of repeated p query params (#​14321)

    • This is because Cloudflare has a hard limit of 100 URL search param key/value pairs when used as a key for caching purposes
    • If more that 100 paths were included, the cache key would be incomplete and could produce false-positive cache hits
  • [UNSTABLE] Add fetcher.unstable_reset() API (#​14206)

  • Made useOutlet element reference have stable identity in-between route chages (#​13382)

  • feat: enable full transition support for the rsc router (#​14362)

  • In RSC Data Mode, handle SSR'd client errors and re-try in the browser (#​14342)

  • Support middleware prop on <Route> for usage with a data router via createRoutesFromElements (#​14357)

  • Handle encoded question mark and hash characters in ancestor splat routes (#​14249)

  • Fail gracefully on manifest version mismatch logic if sessionStorage access is blocked (#​14335)

v7.9.1

Compare Source

Patch Changes
  • Fix internal Future interface naming from middleware -> v8_middleware (#​14327)

v7.9.0

Compare Source

Minor Changes
Patch Changes
  • Escape HTML in meta() JSON-LD content (#​14316)
  • Add react-server Await component implementation (#​14261)
  • In RSC Data Mode when using a custom basename, fix hydration errors for routes that only have client loaders (#​14264)
  • Make href function available in a react-server context (#​14262)
  • decode each time getPayload() is called to allow for "in-context" decoding and hoisting of contextual assets (#​14248)
  • href() now correctly processes routes that have an extension after the parameter or are a single optional parameter. (#​13797)

v7.8.2

Compare Source

Patch Changes
  • [UNSTABLE] Remove Data Mode future.unstable_middleware flag from createBrowserRouter (#​14213)

    • This is only needed as a Framework Mode flag because of the route modules and the getLoadContext type behavior change
    • In Data Mode, it's an opt-in feature because it's just a new property on a route object, so there's no behavior changes that necessitate a flag
  • [UNSTABLE] Add <RouterProvider unstable_onError>/<HydratedRouter unstable_onError> prop for client side error reporting (#​14162)

  • server action revalidation opt out via $SKIP_REVALIDATION field (#​14154)

  • Properly escape interpolated param values in generatePath() (#​13530)

  • Maintain ReadonlyMap and ReadonlySet types in server response data. (#​13092)

  • [UNSTABLE] Delay serialization of .data redirects to 202 responses until after middleware chain (#​14205)

  • Fix TypeError if you throw from patchRoutesOnNavigation when no partial matches exist (#​14198)

  • Fix basename usage without a leading slash in data routers (#​11671)

  • [UNSTABLE] Update client middleware so it returns the data strategy results allowing for more advanced post-processing middleware (#​14151)

v7.8.1

Compare Source

Patch Changes
  • Fix usage of optional path segments in nested routes defined using absolute paths (#​14135)
  • Bubble client pre-next middleware error to the shallowest ancestor that needs to load, not strictly the shallowest ancestor with a loader (#​14150)
  • Fix optional static segment matching in matchPath (#​11813)
  • Fix prerendering when a basename is set with ssr:false (#​13791)
  • Provide isRouteErrorResponse utility in react-server environments (#​14166)
  • Propagate non-redirect Responses thrown from middleware to the error boundary on document/data requests (#​14182)
  • Handle meta and links Route Exports in RSC Data Mode (#​14136)
  • Properly convert returned/thrown data() values to Response instances via Response.json() in resource routes and middleware (#​14159, #​14181)

v7.8.0

Compare Source

Minor Changes
  • Add nonce prop to Links & PrefetchPageLinks (#​14048)
  • Add loaderData arguments/properties alongside existing data arguments/properties to provide consistency and clarity between loaderData and actionData across the board (#​14047)
    • Updated types: Route.MetaArgs, Route.MetaMatch, MetaArgs, MetaMatch, Route.ComponentProps.matches, UIMatch
    • @deprecated warnings have been added to the existing data properties to point users to new loaderData properties, in preparation for removing the data properties in a future major release
Patch Changes
  • Prevent "Did not find corresponding fetcher result" console error when navigating during a fetcher.submit revalidation (#​14114)

  • Bubble client-side middleware errors prior to next to the appropriate ancestor error boundary (#​14138)

  • Switch Lazy Route Discovery manifest URL generation to usea standalone URLSearchParams instance instead of URL.searchParams to avoid a major performance bottleneck in Chrome (#​14084)

  • Adjust internal RSC usage of React.use to avoid Webpack compilation errors when using React 18 (#​14113)

  • Remove dependency on @types/node in TypeScript declaration files (#​14059)

  • Fix types for UIMatch to reflect that the loaderData/data properties may be undefined (#​12206)

    • When an ErrorBoundary is being rendered, not all active matches will have loader data available, since it may have been their loader that threw to trigger the boundary
    • The UIMatch.data type was not correctly handing this and would always reflect the presence of data, leading to the unexpected runtime errors when an ErrorBoundary was rendered
    • ⚠️ This may cause some type errors to show up in your code for unguarded match.data accesses - you should properly guard for undefined values in those scenarios.
    // app/root.tsx
    export function loader() {
      someFunctionThatThrows(); // ❌ Throws an Error
      return { title: "My Title" };
    }
    
    export function Layout({ children }: { children: React.ReactNode }) {
      let matches = useMatches();
      let rootMatch = matches[0] as UIMatch<Awaited<ReturnType<typeof loader>>>;
      //  ^ rootMatch.data is incorrectly typed here, so TypeScript does not
      //    complain if you do the following which throws an error at runtime:
      let { title } = rootMatch.data; // 💥
    
      return <html>...</html>;
    }
  • [UNSTABLE] Ensure resource route errors go through handleError w/middleware enabled (#​14078)

  • [UNSTABLE] Propagate returned Response from server middleware if next wasn't called (#​14093)

  • [UNSTABLE] Allow server middlewares to return data() values which will be converted into a Response (#​14093)

  • [UNSTABLE] Update middleware error handling so that the next function never throws and instead handles any middleware errors at the proper ErrorBoundary and returns the Response up through the ancestor next function (#​14118)

  • [UNSTABLE] When middleware is enabled, make the context parameter read-only (via Readonly<unstable_RouterContextProvider>) so that TypeScript will not allow you to write arbitrary fields to it in loaders, actions, or middleware. (#​14097)

  • [UNSTABLE] Rename and alter the signature/functionality of the unstable_respond API in staticHandler.query/staticHandler.queryRoute (#​14103)

    • The API has been renamed to unstable_generateMiddlewareResponse for clarity
    • The main functional change is that instead of running the loaders/actions before calling unstable_respond and handing you the result, we now pass a query/queryRoute function as a parameter and you execute the loaders/actions inside your callback, giving you full access to pre-processing and error handling
    • The query version of the API now has a signature of (query: (r: Request) => Promise<StaticHandlerContext | Response>) => Promise<Response>
    • The queryRoute version of the API now has a signature of (queryRoute: (r: Request) => Promise<Response>) => Promise<Response>
    • This allows for more advanced usages such as running logic before/after calling query and direct error handling of errors thrown from query
    • ⚠️ This is a breaking change if you've adopted the staticHandler unstable_respond API
    let response = await staticHandler.query(request, {
      requestContext: new unstable_RouterContextProvider(),
      async unstable_generateMiddlewareResponse(query) {
        try {
          // At this point we've run middleware top-down so we need to call the
          // handlers and generate the Response to bubble back up the middleware
          let result = await query(request);
          if (isResponse(result)) {
            return result; // Redirects, etc.
          }
          return await generateHtmlResponse(result);
        } catch (error: unknown) {
          return generateErrorResponse(error);
        }
      },
    });
  • [UNSTABLE] Convert internal middleware implementations to use the new unstable_generateMiddlewareResponse API (#​14103)

  • [UNSTABLE] Change getLoadContext signature (type GetLoadContextFunction) when future.unstable_middleware is enabled so that it returns an unstable_RouterContextProvider instance instead of a Map used to contruct the instance internally (#​14097)

    • This also removes the type unstable_InitialContext export
    • ⚠️ This is a breaking change if you have adopted middleware and are using a custom server with a getLoadContext function
  • [UNSTABLE] Run client middleware on client navigations even if no loaders exist (#​14106)

  • [UNSTABLE] Change the unstable_getContext signature on RouterProvider/HydratedRouter/unstable_RSCHydratedRouter so that it returns an unstable_RouterContextProvider instance instead of a Map used to contruct the instance internally (#​14097)

    • ⚠️ This is a breaking change if you have adopted the unstable_getContext prop
  • [UNSTABLE] proxy server action side-effect redirects from actions for document and callServer requests (#​14131)

  • [UNSTABLE] Fix RSC Data Mode issue where routes that return false from shouldRevalidate would be replaced by an <Outlet /> (#​14071)

v7.7.1

Compare Source

Patch Changes
  • In RSC Data Mode, fix bug where routes with errors weren't forced to revalidate when shouldRevalidate returned false (#​14026)
  • In RSC Data Mode, fix Matched leaf route at location "/..." does not have an element or Component warnings when error boundaries are rendered. (#​14021)

v7.7.0

Compare Source

Minor Changes
Patch Changes
  • Handle InvalidCharacterError when validating cookie signature (#​13847)

  • Pass a copy of searchParams to the setSearchParams callback function to avoid muations of the internal searchParams instance. This was an issue when navigations were blocked because the internal instance be out of sync with useLocation().search. (#​12784)

  • Support invalid Date in turbo-stream v2 fork (#​13684)

  • In Framework Mode, clear critical CSS in development after initial render (#​13872)

  • Strip search parameters from patchRoutesOnNavigation path param for fetcher calls (#​13911)

  • Skip scroll restoration on useRevalidator() calls because they're not new locations (#​13671)

  • Support unencoded UTF-8 routes in prerender config with ssr set to false (#​13699)

  • Do not throw if the url hash is not a valid URI component (#​13247)

  • Fix a regression in createRoutesStub introduced with the middleware feature. (#​13946)

    As part of that work we altered the signature to align with the new middleware APIs without making it backwards compatible with the prior AppLoadContext API. This permitted createRoutesStub to work if you were opting into middleware and the updated context typings, but broke createRoutesStub for users not yet opting into middleware.

    We've reverted this change and re-implemented it in such a way that both sets of users can leverage it.

    // If you have not opted into middleware, the old API should work again
    let context: AppLoadContext = {
      /*...*/
    };
    let Stub = createRoutesStub(routes, context);
    
    // If you have opted into middleware, you should now pass an instantiated `unstable_routerContextProvider` instead of a `getContext` factory function.
    let context = new unstable_RouterContextProvider();
    context.set(SomeContext, someValue);
    let Stub = createRoutesStub(routes, context);

    ⚠️ This may be a breaking bug for if you have adopted the unstable Middleware feature and are using createRoutesStub with the updated API.

  • Remove Content-Length header from Single Fetch responses (#​13902)

v7.6.3

Compare Source

Patch Changes
  • Do not serialize types for useRouteLoaderData<typeof clientLoader> (#​13752)

    For types to distinguish a clientLoader from a serverLoader, you MUST annotate clientLoader args:

    //                                   👇 annotation required to skip serializing types
    export function clientLoader({}: Route.ClientLoaderArgs) {
      return { fn: () => "earth" };
    }
    
    function SomeComponent() {
      const data = useRouteLoaderData<typeof clientLoader>("routes/this-route");
      const planet = data?.fn() ?? "world";
      return <h1>Hello, {planet}!</h1>;
    }

v7.6.2

Compare Source

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)
  • Slight refactor of internal headers() function processing for use with RSC (#​13639)

v7.6.1

Compare Source

Patch Changes
  • Update Route.MetaArgs to reflect that data can be potentially undefined (#​13563)

    This is primarily for cases where a route loader threw an error to it's own ErrorBoundary. but it also arises in the case of a 404 which renders the root ErrorBoundary/meta but the root loader did not run because not routes matched.

  • Partially revert optimization added in 7.1.4 to reduce calls to matchRoutes because it surfaced other issues (#​13562)

  • Fix typegen when same route is used at multiple paths (#​13574)

    For example, routes/route.tsx is used at 4 different paths here:

    import { type RouteConfig, route } from "@&#8203;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.

  • Better types for params (#​13543)

    For example:

    // routes.ts
    import { type RouteConfig, route } from "@&#8203;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:

    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:

    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

  • Avoid initial fetcher execution 404 error when Lazy Route Discovery is interrupted by a navigation (#​13564)

  • href replaces splats * (#​13593)

    const a = href("/products/*", { "*": "/1/edit" });
    // -> /products/1/edit

v7.6.0

Compare Source

Minor Changes
  • Added a new react-router.config.ts routeDiscovery option to configure Lazy Route Discovery behavior. (#​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" }
  • Add support for route component props in createRoutesStub. This allows you to unit test your route components using the props instead of the hooks: (#​13528)

    let RoutesStub = createRoutesStub([
      {
        path: "/",
        Component({ loaderData }) {
          let data = loaderData as { message: string };
          return <pre data-testid="data">Message: {data.message}</pre>;
        },
        loader() {
          return { message: "hello" };
        },
      },
    ]);
    
    render(<RoutesStub />);
    
    await waitFor(() => screen.findByText("Message: hello"));
Patch Changes
  • Fix react-router module augmentation for NodeNext (#​13498)

  • Don't bundle react-router in react-router/dom CJS export (#​13497)

  • Fix bug where a submitting fetcher would get stuck in a loading state if a revalidating loader redirected (#​12873)

  • Fix hydration error if a server loader returned undefined (#​13496)

  • Fix initial load 404 scenarios in data mode (#​13500)

  • Stabilize useRevalidator's revalidate function (#​13542)

  • Preserve status code if a clientAction throws a data() result in framework mode (#​13522)

  • Be defensive against leading double slashes in paths to avoid Invalid URL errors from the URL constructor (#​13510)

    • Note we do not sanitize/normalize these paths - we only detect them so we can avoid the error that would be thrown by new URL("//", window.location.origin)
  • Remove Navigator declaration for navigator.connection.saveData to avoid messing with any other types beyond saveData in userland (#​13512)

  • Fix handleError params values on .data requests for routes with a dynamic param as the last URL segment (#​13481)

  • Don't trigger an ErrorBoundary UI before the reload when we detect a manifest verison mismatch in Lazy Route Discovery (#​13480)

  • Inline turbo-stream@2.4.1 dependency and fix decoding ordering of Map/Set instances (#​13518)

  • Only render dev warnings in DEV mode (#​13461)

  • UNSTABLE: Fix a few bugs with error bubbling in middleware use-cases (#​13538)

  • Short circuit post-processing on aborted dataStrategy requests (#​13521)

    • This resolves non-user-facing console errors of the form Cannot read properties of undefined (reading 'result')

v7.5.3

Compare Source

Patch Changes
  • Fix bug where bubbled action errors would result in loaderData being cleared at the handling ErrorBoundary route (#​13476)
  • Handle redirects from clientLoader.hydrate initial load executions (#​13477)

v7.5.2

Compare Source

Patch Changes
  • Update Single Fetch to also handle the 204 redirects used in ?_data requests in Remix v2 (#​13364)

    • This allows applications to return a redirect on .data requests from outside the scope of React Router (i.e., an express/hono middleware)
    • ⚠️ Please note that doing so relies on implementation details that are subject to change without a SemVer major release
    • This is primarily done to ease upgrading to Single Fetch for existing Remix v2 applications, but the recommended way to handle this is redirecting from a route middleware
  • Adjust approach for Prerendering/SPA Mode via headers (#​13453)

v7.5.1

Compare Source

Patch Changes
  • Fix single fetch bug where no revalidation request would be made when navigating upwards to a reused parent route (#​13253)

  • When using the object-based route.lazy API, the HydrateFallback and hydrateFallbackElement properties are now skipped when lazy loading routes after hydration. (#​13376)

    If you move the code for these properties into a separate file, you can use this optimization to avoid downloading unused hydration code. For example:

    createBrowserRouter([
      {
        path: "/show/:showId",
        lazy: {
          loader: async () => (await import("./show.loader.js")).loader,
          Component: async () => (await import("./show.component.js")).Component,
          HydrateFallback: async () =>
            (await import("./show.hydrate-fallback.js")).HydrateFallback,
        },
      },
    ]);
  • Properly revalidate prerendered paths when param values change (#​13380)

  • UNSTABLE: Add a new unstable_runClientMiddleware argument to dataStrategy to enable middleware execution in custom dataStrategy implementations (#​13395)

  • UNSTABLE: Add better error messaging when getLoadContext is not updated to return a Map" (#​13242)

  • Do not automatically add null to staticHandler.query() context.loaderData if routes do not have loaders (#​13223)

    • This was a Remix v2 implementation detail inadvertently left in for React Router v7
    • Now that we allow returning undefined from loaders, our prior check of loaderData[routeId] !== undefined was no longer sufficient and was changed to a routeId in loaderData check - these null values can cause issues for this new check
    • ⚠️ This could be a "breaking bug fix" for you if you are doing manual SSR with createStaticHandler()/<StaticRouterProvider>, and using context.loaderData to control <RouterProvider> hydration behavior on the client
  • Fix prerendering when a loader returns a redirect (#​13365)

  • UNSTABLE: Update context type for LoaderFunctionArgs/ActionFunctionArgs when middleware is enabled (#​13381)

  • Add support for the new unstable_shouldCallHandler/unstable_shouldRevalidateArgs APIs in dataStrategy (#​13253)

v7.5.0

Compare Source

Minor Changes
  • Add granular object-based API for route.lazy to support lazy loading of individual route properties, for example: (#​13294)

    createBrowserRouter([
      {
        path: "/show/:showId",
        lazy: {
          loader: async () => (await import("./show.loader.js")).loader,
          action: async () => (await import("./show.action.js")).action,
          Component: async () => (await import("./show.component.js")).Component,
        },
      },
    ]);

    Breaking change for route.unstable_lazyMiddleware consumers

    The route.unstable_lazyMiddleware property is no longer supported. If you want to lazily load middleware, you must use the new object-based route.lazy API with route.lazy.unstable_middleware, for example:

    createBrowserRouter([
      {
        path: "/show/:showId",
        lazy: {
          unstable_middleware: async () =>
            (await import("./show.middleware.js")).middleware,
          // etc.
        },
      },
    ]);
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)

v7.4.1

Compare Source

Patch Changes
  • Fix types on unstable_MiddlewareFunction to avoid type errors when a middleware doesn't return a value (#​13311)

  • Dedupe calls to route.lazy functions (#​13260)

  • Add support for route.unstable_lazyMiddleware function to allow lazy loading of middleware logic. (#​13210)

    Breaking change for unstable_middleware consumers

    The route.unstable_middleware property is no longer supported in the return value from route.lazy. If you want to lazily load middleware, you must use route.unstable_lazyMiddleware.

v7.4.0

Compare Source

Patch Changes
  • Fix root loader data on initial load redirects in SPA mode (#​13222)
  • Load ancestor pathless/index routes in lazy route discovery for upwards non-eager-discoery routing (#​13203)
  • Fix shouldRevalidate behavior for clientLoader-only routes in ssr:true apps (#​13221)
  • UNSTABLE: Fix RequestHandler loadContext parameter type when middleware is enabled (#​13204)
  • UNSTABLE: Update Route.unstable_MiddlewareFunction to have a return value of Response | undefined instead of Response | void becaue you should not return anything if you aren't returning the Response (#​13199)
  • UNSTABLE(BREAKING): If a middleware throws an error, ensure we only bubble the error itself via next() and are no longer leaking the MiddlewareError implementation detail (#​13180)

v7.3.0

Compare Source

Minor Changes
  • Add fetcherKey as a parameter to patchRoutesOnNavigation (#​13061)
    • In framework mode, Lazy Route Discovery will now detect manifest version mismatches after a new deploy
    • On navigations to undiscovered routes, this mismatch will trigger a document reload of the destination path
    • On fetcher calls to undiscovered routes, this mismatch will trigger a document reload of the current path
Patch Changes
  • Skip resource route flow in dev server in SPA mode (#​13113)

  • Support middleware on routes (unstable) (#​12941)

    Middleware is implemented behind a future.unstable_middleware flag. To enable, you must enable the flag and the types in your react-router-config.ts file:

    import type { Config } from "@&#8203;react-router/dev/config";
    import type { Future } from "react-router";
    
    declare module "react-router" {
      interface Future {
        unstable_middleware: true; // 👈 Enable middleware types
      }
    }
    
    export default {
      future: {
        unstable_middleware: true, // 👈 Enable middleware
      },
    } satisfies Config;

    ⚠️ Middleware is unstable and should not be adopted in production. There is at least one known de-optimization in route module loading for clientMiddleware that we will be addressing this before a stable release.

    ⚠️ Enabling middleware contains a breaking change to the context parameter passed to your loader/action functions - see below for more information.

    Once enabled, routes can define an array of middleware functions that will run sequentially before route handlers run. These functions accept the same parameters as loader/action plus an additional next parameter to run the remaining data pipeline. This allows middlewares to perform logic before and after handlers execute.

    // Framework mode
    export const unstable_middleware = [serverLogger, serverAuth]; // server
    export const unstable_clientMiddleware = [clientLogger]; // client
    
    // Library mode
    const routes = [
      {
        path: "/",
        // Middlewares are client-side for library mode SPA's
        unstable_middleware: [clientLogger, clientAuth],
        loader: rootLoader,
        Component: Root,
      },
    ];

    Here's a simple example of a client-side logging middleware that can be placed on the root route:

    const clientLogger: Route.unstable_ClientMiddlewareFunction = async (
      { request },
      next,
    ) => {
      let start = performance.now();
    
      // Run the remaining middlewares and all route loaders
      await next();
    
      let duration = performance.now() - start;
      console.log(`Navigated to ${request.url} (${duration}ms)`);
    };

    Note that in the above example, the next/middleware functions don't return anything. This is by design as on the client there is no "response" to send over the network like there would be for middlewares running on the server. The data is all handled behind the scenes by the stateful router.

    For a server-side middleware, the next function will return the HTTP Response that React Router will be sending across the wire, thus giving you a chance to make changes as needed. You may throw a new response to short circuit and respond immediately, or you may return a new or altered response to override the default returned by next().

    const serverLogger: Route.unstable_MiddlewareFunction = async (
      { request, params, context },
      next,
    ) => {
      let start = performance.now();
    
      // 👇 Grab the response here
      let res = await next();
    
      let duration = performance.now() - start;
      console.log(`Navigated to ${request.url} (${duration}ms)`);
    
      // 👇 And return it here (optional if you don't modify the response)
      return res;
    };

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

    import { sessionContext } from "../context";
    const serverAuth: Route.unstable_MiddlewareFunction = (
      { request, params, context },
      next,
    ) => {
      let session = context.get(sessionContext);
      let user = session.get("user");
      if (!user) {
        session.set("returnTo", request.url);
        throw redirect("/login", 302);
      }
    };

    Note that in cases like this where you don't need to do any post-processing you don't need to call the next function or return a Response.

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

    const redirects: Route.unstable_MiddlewareFunction = async ({
      request,
      next,
    }) => {
      // attempt to handle the request
      let res = await next();
    
      // if it's a 404, check the CMS for a redirect, do it last
      // because it's expensive
      if (res.status === 404) {
        let cmsRedirect = await checkCMSRedirects

Configuration

📅 Schedule: Branch creation - "before 3am on the first day of the month" in timezone America/New_York, Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@cypress-app-bot
Copy link

See the guidelines for reviewing dependency updates for info on how to review dependency update PRs.

@renovate renovate bot force-pushed the renovate/major-react-router branch from 8250c78 to 8837686 Compare June 1, 2024 05:05
@renovate renovate bot force-pushed the renovate/major-react-router branch from 8837686 to a7293cc Compare July 1, 2024 04:40
@renovate renovate bot force-pushed the renovate/major-react-router branch from a7293cc to b8366f3 Compare August 1, 2024 06:49
@renovate renovate bot force-pushed the renovate/major-react-router branch from b8366f3 to 23e1b5b Compare October 1, 2024 06:28
@renovate renovate bot force-pushed the renovate/major-react-router branch from 23e1b5b to 2833aa7 Compare December 1, 2024 06:42
@renovate renovate bot force-pushed the renovate/major-react-router branch from 2833aa7 to 45b303a Compare March 1, 2025 06:16
@renovate renovate bot force-pushed the renovate/major-react-router branch from 45b303a to 2972643 Compare April 1, 2025 06:57
@renovate renovate bot force-pushed the renovate/major-react-router branch from 2972643 to b249ddf Compare June 1, 2025 05:33
@renovate renovate bot force-pushed the renovate/major-react-router branch from b249ddf to 1340126 Compare August 1, 2025 04:52
@renovate renovate bot force-pushed the renovate/major-react-router branch from 1340126 to 4c4e034 Compare November 1, 2025 04:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants