Frontend Enhancements: - Complete React TypeScript frontend with modern UI components - Distributed workflows management interface with real-time updates - Socket.IO integration for live agent status monitoring - Agent management dashboard with cluster visualization - Project management interface with metrics and task tracking - Responsive design with proper error handling and loading states Backend Infrastructure: - Distributed coordinator for multi-agent workflow orchestration - Cluster management API with comprehensive agent operations - Enhanced database models for agents and projects - Project service for filesystem-based project discovery - Performance monitoring and metrics collection - Comprehensive API documentation and error handling Documentation: - Complete distributed development guide (README_DISTRIBUTED.md) - Comprehensive development report with architecture insights - System configuration templates and deployment guides The platform now provides a complete web interface for managing the distributed AI cluster with real-time monitoring, workflow orchestration, and agent coordination capabilities. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
52 KiB
@remix-run/router
1.23.0
Minor Changes
- Add
fetcherKeyas a parameter topatchRoutesOnNavigation(#13109)
Patch Changes
- Fix regression introduced in
6.29.0via #12169 that caused issues navigating to hash routes inside splat routes for applications using Lazy Route Discovery (patchRoutesOnNavigation) (#13108)
1.22.0
Minor Changes
-
Provide the request
signalas a parameter topatchRoutesOnNavigation(#12900)- This can be used to abort any manifest fetches if the in-flight navigation/fetcher is aborted
Patch Changes
- Do not log v7 deprecation warnings in production builds (#12794)
- Strip search parameters from
patchRoutesOnNavigationpathparam for fetcher calls (#12899) - Properly bubble headers when throwing a
data()result (#12845) - Optimize route matching by skipping redundant
matchRoutescalls when possible (#12169)
1.21.1
Patch Changes
-
- Fix issue with fetcher data cleanup in the data layer on fetcher unmount (#12674)
- Fix behavior of manual fetcher keys when not opted into
future.v7_fetcherPersist
1.21.0
Minor Changes
-
- Log deprecation warnings for v7 flags (#11750)
- Add deprecation warnings to
json/deferin favor of returning raw objects- These methods will be removed in React Router v7
Patch Changes
- Update JSDoc URLs for new website structure (add /v6/ segment) (#12141)
1.20.0
Minor Changes
- Stabilize
unstable_patchRoutesOnNavigation(#11973)- Add new
PatchRoutesOnNavigationFunctionArgstype for convenience (#11967)
- Add new
- Stabilize
unstable_dataStrategy(#11974) - Stabilize the
unstable_flushSyncoption for navigations and fetchers (#11989) - Stabilize the
unstable_viewTransitionoption for navigations and the correspondingunstable_useViewTransitionStatehook (#11989)
Patch Changes
- Fix bug when submitting to the current contextual route (parent route with an index child) when an
?indexparam already exists from a prior submission (#12003) - Fix
useFormActionbug - when removing?indexparam it would not keep other non-Remixindexparams (#12003) - Fix bug with fetchers not persisting
preventScrollResetthrough redirects during concurrent fetches (#11999) - Remove internal cache to fix issues with interrupted
patchRoutesOnNavigationcalls (#12055)- We used to cache in-progress calls to
patchRoutesOnNavigationinternally so that multiple navigations with the same start/end would only execute the function once and use the same promise - However, this approach was at odds with
patchshort circuiting if a navigation was interrupted (and therequest.signalaborted) since the first invocation'spatchwould no-op - This cache also made some assumptions as to what a valid cache key might be - and is oblivious to any other application-state changes that may have occurred
- So, the cache has been removed because in most cases, repeated calls to something like
import()for async routes will already be cached automatically - and if not it's easy enough for users to implement this cache in userland
- We used to cache in-progress calls to
- Avoid unnecessary
console.erroron fetcher abort due to back-to-back revalidation calls (#12050) - Expose errors thrown from
patchRoutesOnNavigationdirectly touseRouteErrorinstead of wrapping them in a 400ErrorResponseinstance (#12111) - Fix types for
RouteObjectwithinPatchRoutesOnNavigationFunction'spatchmethod so it doesn't expect agnostic route objects passed topatch(#11967) - Fix bugs with
partialHydrationwhen hydrating with errors (#12070) - Remove internal
discoveredRoutesFIFO queue fromunstable_patchRoutesOnNavigation(#11977)
1.19.2
Patch Changes
- Update the
unstable_dataStrategyAPI to allow for more advanced implementations (#11943)- Rename
unstable_HandlerResulttounstable_DataStrategyResult - The return signature has changed from a parallel array of
unstable_DataStrategyResult[](parallel tomatches) to a key/value object ofrouteId => unstable_DataStrategyResult- This allows you to more easily decide to opt-into or out-of revalidating data that may not have been revalidated by default (via
match.shouldLoad) - ⚠️ This is a breaking change if you've currently adopted
unstable_dataStrategy
- This allows you to more easily decide to opt-into or out-of revalidating data that may not have been revalidated by default (via
- Added a new
fetcherKeyparameter tounstable_dataStrategyto allow differentiation from navigational and fetcher calls - You should now return/throw a result from your
handlerOverrideinstead of returning aDataStrategyResult- If you are aggregating the results of
match.resolve()into a final results object you should not need to think about theDataStrategyResulttype - If you are manually filling your results object from within your
handlerOverride, then you will need to assign aDataStrategyResultas the value so React Router knows if it's a successful execution or an error.
- If you are aggregating the results of
- Rename
- Preserve view transition through redirects (#11925)
- Fix blocker usage when
blocker.proceedis called quickly/synchronously (#11930) - Preserve pending view transitions through a router revalidation call (#11917)
1.19.1
Patch Changes
-
Fog of War: Update
unstable_patchRoutesOnMisslogic so that we call the method when we match routes with dynamic param or splat segments in case there exists a higher-scoring static route that we've not yet discovered. (#11883)- We also now leverage an internal FIFO queue of previous paths we've already called
unstable_patchRouteOnMissagainst so that we don't re-call on subsequent navigations to the same path
- We also now leverage an internal FIFO queue of previous paths we've already called
-
Rename
unstable_patchRoutesOnMisstounstable_patchRoutesOnNavigationto match new behavior (#11888)
1.19.0
Minor Changes
- Add a new
replace(url, init?)alternative toredirect(url, init?)that performs ahistory.replaceStateinstead of ahistory.pushStateon client-side navigation redirects (#11811) - Add a new
unstable_data()API for usage with Remix Single Fetch (#11836)- This API is not intended for direct usage in React Router SPA applications
- It is primarily intended for usage with
createStaticHandler.query()to allow loaders/actions to return arbitrary data +status/headerswithout forcing the serialization of data into aResponseinstance - This allows for more advanced serialization tactics via
unstable_dataStrategysuch as serializing viaturbo-streamin Remix Single Fetch - ⚠️ This removes the
statusfield fromHandlerResult- If you need to return a specific
statusfromunstable_dataStrategyyou should instead do so viaunstable_data()
- If you need to return a specific
Patch Changes
- Fix internal cleanup of interrupted fetchers to avoid invalid revalidations on navigations (#11839)
- When a
fetcher.loadis interrupted by anactionsubmission, we track it internally and force revalidation once theactioncompletes - We previously only cleared out this internal tracking info on a successful navigation submission
- Therefore, if the
fetcher.loadwas interrupted by afetcher.submit, then we wouldn't remove it from this internal tracking info on successful load (incorrectly) - And then on the next navigation it's presence in the internal tracking would automatically trigger execution of the
fetcher.loadagain, ignoring anyshouldRevalidatelogic - This fix cleans up the internal tracking so it applies to both navigation submission and fetcher submissions
- When a
- Fix initial hydration behavior when using
future.v7_partialHydrationalong withunstable_patchRoutesOnMiss(#11838)- During initial hydration,
router.state.matcheswill now include any partial matches so that we can render ancestorHydrateFallbackcomponents
- During initial hydration,
1.18.0
Minor Changes
- Stabilize
future.unstable_skipActionErrorRevalidationasfuture.v7_skipActionErrorRevalidation(#11769)- When this flag is enabled, actions will not automatically trigger a revalidation if they return/throw a
Responsewith a4xx/5xxstatus code - You may still opt-into revalidation via
shouldRevalidate - This also changes
shouldRevalidate'sunstable_actionStatusparameter toactionStatus
- When this flag is enabled, actions will not automatically trigger a revalidation if they return/throw a
Patch Changes
- Fix bubbling of errors thrown from
unstable_patchRoutesOnMiss(#11786) - Fix hydration in SSR apps using
unstable_patchRoutesOnMissthat matched a splat route on the server (#11790)
1.17.1
Patch Changes
- Fog of War (unstable): Trigger a new
router.routesidentity/reflow during route patching (#11740) - Fog of War (unstable): Fix initial matching when a splat route matches (#11759)
1.17.0
Minor Changes
-
Add support for Lazy Route Discovery (a.k.a. Fog of War) (#11626)
- RFC: https://github.com/remix-run/react-router/discussions/11113
unstable_patchRoutesOnMissdocs: https://reactrouter.com/v6/routers/create-browser-router
1.16.1
Patch Changes
- Support
unstable_dataStrategyonstaticHandler.queryRoute(#11515)
1.16.0
Minor Changes
- Add a new
unstable_dataStrategyconfiguration option (#11098)- This option allows Data Router applications to take control over the approach for executing route loaders and actions
- The default implementation is today's behavior, to fetch all loaders in parallel, but this option allows users to implement more advanced data flows including Remix single-fetch, middleware/context APIs, automatic loader caching, and more
- Move
unstable_dataStrategyfromcreateStaticHandlertostaticHandler.queryso it can be request-specific for use with theResponseStubapproach in Remix. It's not really applicable toqueryRoutefor now since that's a singular handler call anyway so any pre-processing/post/processing could be done there manually. (#11377) - Add a new
future.unstable_skipActionRevalidationfuture flag (#11098)- Currently, active loaders revalidate after any action, regardless of the result
- With this flag enabled, actions that return/throw a 4xx/5xx response status will no longer automatically revalidate
- This should reduce load on your server since it's rare that a 4xx/5xx should actually mutate any data
- If you need to revalidate after a 4xx/5xx result with this flag enabled, you can still do that via returning
truefromshouldRevalidate shouldRevalidatenow also receives a newunstable_actionStatusargument alongsideactionResultso you can make decision based on the status of theactionresponse without having to encode it into the action data
- Added a
skipLoaderErrorBubblingflag tostaticHandler.queryto disable error bubbling on loader executions for single-fetch scenarios where the client-side router will handle the bubbling (#11098)
1.15.3
Patch Changes
- Fix a
future.v7_partialHydrationbug that would re-run loaders below the boundary on hydration if SSR loader errors bubbled to a parent boundary (#11324) - Fix a
future.v7_partialHydrationbug that would consider the router uninitialized if a route did not have a loader (#11325)
1.15.2
Patch Changes
- Preserve hydrated errors during partial hydration runs (#11305)
1.15.1
Patch Changes
- Fix encoding/decoding issues with pre-encoded dynamic parameter values (#11199)
1.15.0
Minor Changes
-
Add a
createStaticHandlerfuture.v7_throwAbortReasonflag to throwrequest.signal.reason(defaults to aDOMException) when a request is aborted instead of anErrorsuch asnew Error("query() call aborted: GET /path")(#11104)- Please note that
DOMExceptionwas added in Node v17 so you will not get aDOMExceptionon Node 16 and below.
- Please note that
Patch Changes
- Respect the
ErrorResponsestatus code if passed togetStaticContextFormError(#11213)
1.14.2
Patch Changes
- Fix bug where dashes were not picked up in dynamic parameter names (#11160)
- Do not attempt to deserialize empty JSON responses (#11164)
1.14.1
Patch Changes
- Fix bug with
route.lazynot working correctly on initial SPA load whenv7_partialHydrationis specified (#11121) - Fix bug preventing revalidation from occurring for persisted fetchers unmounted during the
submittingphase (#11102) - De-dup relative path logic in
resolveTo(#11097)
1.14.0
Minor Changes
-
Added a new
future.v7_partialHydrationfuture flag that enables partial hydration of a data router when Server-Side Rendering. This allows you to providehydrationData.loaderDatathat has values for some initially matched route loaders, but not all. When this flag is enabled, the router will callloaderfunctions for routes that do not have hydration loader data duringrouter.initialize(), and it will render down to the deepest providedHydrateFallback(up to the first route without hydration data) while it executes the unhydrated routes. (#11033)For example, the following router has a
rootandindexroute, but only providedhydrationData.loaderDatafor therootroute. Because theindexroute has aloader, we need to run that during initialization. Withfuture.v7_partialHydrationspecified,<RouterProvider>will render theRootComponent(because it has data) and then theIndexFallback(since it does not have data). OnceindexLoaderfinishes, application will update and displayIndexComponent.let router = createBrowserRouter( [ { id: "root", path: "/", loader: rootLoader, Component: RootComponent, Fallback: RootFallback, children: [ { id: "index", index: true, loader: indexLoader, Component: IndexComponent, HydrateFallback: IndexFallback, }, ], }, ], { future: { v7_partialHydration: true, }, hydrationData: { loaderData: { root: { message: "Hydrated from Root!" }, }, }, } );If the above example did not have an
IndexFallback, thenRouterProviderwould instead render theRootFallbackwhile it executed theindexLoader.Note: When
future.v7_partialHydrationis provided, the<RouterProvider fallbackElement>prop is ignored since you can move it to aFallbackon your top-most route. ThefallbackElementprop will be removed in React Router v7 whenv7_partialHydrationbehavior becomes the standard behavior. -
Add a new
future.v7_relativeSplatPathflag to implement a breaking bug fix to relative routing when inside a splat route. (#11087)This fix was originally added in #10983 and was later reverted in #11078 because it was determined that a large number of existing applications were relying on the buggy behavior (see #11052)
The Bug The buggy behavior is that without this flag, the default behavior when resolving relative paths is to ignore any splat (
*) portion of the current route path.The Background This decision was originally made thinking that it would make the concept of nested different sections of your apps in
<Routes>easier if relative routing would replace the current splat:<BrowserRouter> <Routes> <Route path="/" element={<Home />} /> <Route path="dashboard/*" element={<Dashboard />} /> </Routes> </BrowserRouter>Any paths like
/dashboard,/dashboard/team,/dashboard/projectswill match theDashboardroute. The dashboard component itself can then render nested<Routes>:function Dashboard() { return ( <div> <h2>Dashboard</h2> <nav> <Link to="/">Dashboard Home</Link> <Link to="team">Team</Link> <Link to="projects">Projects</Link> </nav> <Routes> <Route path="/" element={<DashboardHome />} /> <Route path="team" element={<DashboardTeam />} /> <Route path="projects" element={<DashboardProjects />} /> </Routes> </div> ); }Now, all links and route paths are relative to the router above them. This makes code splitting and compartmentalizing your app really easy. You could render the
Dashboardas its own independent app, or embed it into your large app without making any changes to it.The Problem
The problem is that this concept of ignoring part of a path breaks a lot of other assumptions in React Router - namely that
"."always means the current location pathname for that route. When we ignore the splat portion, we start getting invalid paths when using".":// If we are on URL /dashboard/team, and we want to link to /dashboard/team: function DashboardTeam() { // ❌ This is broken and results in <a href="/dashboard"> return <Link to=".">A broken link to the Current URL</Link>; // ✅ This is fixed but super unintuitive since we're already at /dashboard/team! return <Link to="./team">A broken link to the Current URL</Link>; }We've also introduced an issue that we can no longer move our
DashboardTeamcomponent around our route hierarchy easily - since it behaves differently if we're underneath a non-splat route, such as/dashboard/:widget. Now, our"."links will, properly point to ourself inclusive of the dynamic param value so behavior will break from it's corresponding usage in a/dashboard/*route.Even worse, consider a nested splat route configuration:
<BrowserRouter> <Routes> <Route path="dashboard"> <Route path="*" element={<Dashboard />} /> </Route> </Routes> </BrowserRouter>Now, a
<Link to=".">and a<Link to="..">inside theDashboardcomponent go to the same place! That is definitely not correct!Another common issue arose in Data Routers (and Remix) where any
<Form>should post to it's own routeactionif you the user doesn't specify a form action:let router = createBrowserRouter({ path: "/dashboard", children: [ { path: "*", action: dashboardAction, Component() { // ❌ This form is broken! It throws a 405 error when it submits because // it tries to submit to /dashboard (without the splat value) and the parent // `/dashboard` route doesn't have an action return <Form method="post">...</Form>; }, }, ], });This is just a compounded issue from the above because the default location for a
Formto submit to is itself (".") - and if we ignore the splat portion, that now resolves to the parent route.The Solution If you are leveraging this behavior, it's recommended to enable the future flag, move your splat to it's own route, and leverage
../for any links to "sibling" pages:<BrowserRouter> <Routes> <Route path="dashboard"> <Route index path="*" element={<Dashboard />} /> </Route> </Routes> </BrowserRouter> function Dashboard() { return ( <div> <h2>Dashboard</h2> <nav> <Link to="..">Dashboard Home</Link> <Link to="../team">Team</Link> <Link to="../projects">Projects</Link> </nav> <Routes> <Route path="/" element={<DashboardHome />} /> <Route path="team" element={<DashboardTeam />} /> <Route path="projects" element={<DashboardProjects />} /> </Router> </div> ); }This way,
.means "the full current pathname for my route" in all cases (including static, dynamic, and splat routes) and..always means "my parents pathname".
Patch Changes
- Catch and bubble errors thrown when trying to unwrap responses from
loader/actionfunctions (#11061) - Fix
relative="path"issue when renderingLink/NavLinkoutside of matched routes (#11062)
1.13.1
Patch Changes
- Revert the
useResolvedPathfix for splat routes due to a large number of applications that were relying on the buggy behavior (see https://github.com/remix-run/react-router/issues/11052#issuecomment-1836589329). We plan to re-introduce this fix behind a future flag in the next minor version. (#11078)
1.13.0
Minor Changes
- Export the
PathParamtype from the public API (#10719)
Patch Changes
- Fix bug with
resolveToin splat routes (#11045)- This is a follow up to #10983 to handle the few other code paths using
getPathContributingMatches - This removes the
UNSAFE_getPathContributingMatchesexport from@remix-run/routersince we no longer need this in thereact-router/react-router-domlayers
- This is a follow up to #10983 to handle the few other code paths using
- Do not revalidate unmounted fetchers when
v7_fetcherPersistis enabled (#11044)
1.12.0
Minor Changes
- Add
unstable_flushSyncoption torouter.navigateandrouter.fetchto tell the React Router layer to opt-out ofReact.startTransitionand intoReactDOM.flushSyncfor state updates (#11005)
Patch Changes
-
Fix
relative="path"bug where relative path calculations started from the full location pathname, instead of from the current contextual route pathname. (#11006)<Route path="/a"> <Route path="/b" element={<Component />}> <Route path="/c" /> </Route> </Route>; function Component() { return ( <> {/* This is now correctly relative to /a/b, not /a/b/c */} <Link to=".." relative="path" /> <Outlet /> </> ); }
1.11.0
Minor Changes
-
Add a new
future.v7_fetcherPersistflag to the@remix-run/routerto change the persistence behavior of fetchers whenrouter.deleteFetcheris called. Instead of being immediately cleaned up, fetchers will persist until they return to anidlestate (RFC) (#10962)- This is sort of a long-standing bug fix as the
useFetchers()API was always supposed to only reflect in-flight fetcher information for pending/optimistic UI -- it was not intended to reflect fetcher data or hang onto fetchers after they returned to anidlestate - Keep an eye out for the following specific behavioral changes when opting into this flag and check your app for compatibility:
- Fetchers that complete while still mounted will no longer appear in
useFetchers(). They served effectively no purpose in there since you can access the data viauseFetcher().data). - Fetchers that previously unmounted while in-flight will not be immediately aborted and will instead be cleaned up once they return to an
idlestate. They will remain exposed viauseFetcherswhile in-flight so you can still access pending/optimistic data after unmount.
- Fetchers that complete while still mounted will no longer appear in
- This is sort of a long-standing bug fix as the
-
When
v7_fetcherPersistis enabled, the router now performs ref-counting on fetcher keys viagetFetcher/deleteFetcherso it knows when a given fetcher is totally unmounted from the UI (#10977)- Once a fetcher has been totally unmounted, we can ignore post-processing of a persisted fetcher result such as a redirect or an error
- The router will also pass a new
deletedFetchersarray to the subscriber callbacks so that the UI layer can remove associated fetcher data
-
Add support for optional path segments in
matchPath(#10768)
Patch Changes
- Fix
router.getFetcher/router.deleteFetchertype definitions which incorrectly specifiedkeyas an optional parameter (#10960)
1.10.0
Minor Changes
- Add experimental support for the View Transitions API by allowing users to opt-into view transitions on navigations via the new
unstable_viewTransitionoption torouter.navigate(#10916)
Patch Changes
- Allow 404 detection to leverage root route error boundary if path contains a URL segment (#10852)
- Fix
ErrorResponsetype to avoid leaking internal field (#10876)
1.9.0
Minor Changes
- In order to move towards stricter TypeScript support in the future, we're aiming to replace current usages of
anywithunknownon exposed typings for user-provided data. To do this in Remix v2 without introducing breaking changes in React Router v6, we have added generics to a number of shared types. These continue to default toanyin React Router and are overridden withunknownin Remix. In React Router v7 we plan to move these tounknownas a breaking change. (#10843)Locationnow accepts a generic for thelocation.statevalueActionFunctionArgs/ActionFunction/LoaderFunctionArgs/LoaderFunctionnow accept a generic for thecontextparameter (only used in SSR usages viacreateStaticHandler)- The return type of
useMatches(now exported asUIMatch) accepts generics formatch.dataandmatch.handle- both of which were already set tounknown
- Move the
@privateclass exportErrorResponseto anUNSAFE_ErrorResponseImplexport since it is an implementation detail and there should be no construction ofErrorResponseinstances in userland. This frees us up to export atype ErrorResponsewhich correlates to an instance of the class viaInstanceType. Userland code should only ever be usingErrorResponseas a type and should be type-narrowing viaisRouteErrorResponse. (#10811) - Export
ShouldRevalidateFunctionArgsinterface (#10797) - Removed private/internal APIs only required for the Remix v1 backwards compatibility layer and no longer needed in Remix v2 (
_isFetchActionRedirect,_hasFetcherDoneAnything) (#10715)
Patch Changes
- Add method/url to error message on aborted
query/queryRoutecalls (#10793) - Fix a race-condition with loader/action-thrown errors on
route.lazyroutes (#10778) - Fix type for
actionResulton the arguments object passed toshouldRevalidate(#10779)
1.8.0
Minor Changes
- Add's a new
redirectDocument()function which allows users to specify that a redirect from aloader/actionshould trigger a document reload (viawindow.location) instead of attempting to navigate to the redirected location via React Router (#10705)
Patch Changes
- Fix an issue in
queryRoutethat was not always identifying thrownResponseinstances (#10717) - Ensure hash history always includes a leading slash on hash pathnames (#10753)
1.7.2
Patch Changes
- Trigger an error if a
deferpromise resolves/rejects withundefinedin order to match the behavior of loaders and actions which must return a value ornull(#10690) - Properly handle fetcher redirects interrupted by normal navigations (#10674, #10709)
- Initial-load fetchers should not automatically revalidate on GET navigations (#10688)
- Enhance the return type of
Route.lazyto prohibit returning an empty object (#10634)
1.7.1
Patch Changes
- Fix issues with reused blockers on subsequent navigations (#10656)
1.7.0
Minor Changes
-
Add support for
application/jsonandtext/plainencodings forrouter.navigate/router.fetchsubmissions. To leverage these encodings, pass your data in abodyparameter and specify the desiredformEncType: (#10413)// By default, the encoding is "application/x-www-form-urlencoded" router.navigate("/", { formMethod: "post", body: { key: "value" }, }); async function action({ request }) { // await request.formData() => FormData instance with entry [key=value] }// Pass `formEncType` to opt-into a different encoding (json) router.navigate("/", { formMethod: "post", formEncType: "application/json", body: { key: "value" }, }); async function action({ request }) { // await request.json() => { key: "value" } }// Pass `formEncType` to opt-into a different encoding (text) router.navigate("/", { formMethod: "post", formEncType: "text/plain", body: "Text submission", }); async function action({ request }) { // await request.text() => "Text submission" }
Patch Changes
- Call
window.history.pushState/replaceStatebefore updating React Router state (instead of after) so thatwindow.locationmatchesuseLocationduring synchronous React 17 rendering (#10448)- ⚠️ However, generally apps should not be relying on
window.locationand should always referenceuseLocationwhen possible, aswindow.locationwill not be in sync 100% of the time (due topopstateevents, concurrent mode, etc.)
- ⚠️ However, generally apps should not be relying on
- Strip
basenamefrom thelocationprovided to<ScrollRestoration getKey>to match theuseLocationbehavior (#10550) - Avoid calling
shouldRevalidatefor fetchers that have not yet completed a data load (#10623) - Fix
unstable_useBlockerkey issues inStrictMode(#10573) - Upgrade
typescriptto 5.1 (#10581)
1.6.3
Patch Changes
- Allow fetcher revalidations to complete if submitting fetcher is deleted (#10535)
- Re-throw
DOMException(DataCloneError) when attempting to perform aPUSHnavigation with non-serializable state. (#10427) - Ensure revalidations happen when hash is present (#10516)
- upgrade jest and jsdom (#10453)
1.6.2
Patch Changes
- Fix HMR-driven error boundaries by properly reconstructing new routes and
manifestin\_internalSetRoutes(#10437) - Fix bug where initial data load would not kick off when hash is present (#10493)
1.6.1
Patch Changes
- Fix
basenamehandling when navigating without a path (#10433) - "Same hash" navigations no longer re-run loaders to match browser behavior (i.e.
/path#hash -> /path#hash) (#10408)
1.6.0
Minor Changes
-
Enable relative routing in the
@remix-run/routerwhen providing a source route ID from which the path is relative to: (#10336)- Example:
router.navigate("../path", { fromRouteId: "some-route" }). - This also applies to
router.fetchwhich already receives a source route ID
- Example:
-
Introduce a new
@remix-run/routerfuture.v7_prependBasenameflag to enablebasenameprefixing to all paths coming intorouter.navigateandrouter.fetch.- Previously the
basenamewas prepended in the React Router layer, but now that relative routing is being handled by the router we need prepend thebasenameafter resolving any relative paths - This also enables
basenamesupport inuseFetcheras well
- Previously the
Patch Changes
- Enhance
LoaderFunction/ActionFunctionreturn type to preventundefinedfrom being a valid return value (#10267) - Ensure proper 404 error on
fetcher.loadcall to a route without aloader(#10345) - Deprecate the
createRouterdetectErrorBoundaryoption in favor of the newmapRoutePropertiesoption for converting a framework-agnostic route to a framework-aware route. This allows us to set more than just thehasErrorBoundaryproperty during route pre-processing, and is now used for mappingComponent -> elementandErrorBoundary -> errorElementinreact-router. (#10287) - Fixed a bug where fetchers were incorrectly attempting to revalidate on search params changes or routing to the same URL (using the same logic for route
loaderrevalidations). However, since fetchers have a static href, they should only revalidate onactionsubmissions orrouter.revalidatecalls. (#10344) - Decouple
AbortControllerusage between revalidating fetchers and the thing that triggered them such that the unmount/deletion of a revalidating fetcher doesn't impact the ongoing triggering navigation/revalidation (#10271)
1.5.0
Minor Changes
-
Added support for Future Flags in React Router. The first flag being introduced is
future.v7_normalizeFormMethodwhich will normalize the exposeduseNavigation()/useFetcher()formMethodfields as uppercase HTTP methods to align with thefetch()behavior. (#10207)- When
future.v7_normalizeFormMethod === false(default v6 behavior),useNavigation().formMethodis lowercaseuseFetcher().formMethodis lowercase
- When
future.v7_normalizeFormMethod === true:useNavigation().formMethodis uppercaseuseFetcher().formMethodis uppercase
- When
Patch Changes
- Provide fetcher submission to
shouldRevalidateif the fetcher action redirects (#10208) - Properly handle
lazy()errors during router initialization (#10201) - Remove
instanceofcheck forDeferredDatato be resilient to ESM/CJS boundaries in SSR bundling scenarios (#10247) - Update to latest
@remix-run/web-fetch@4.3.3(#10216)
1.4.0
Minor Changes
-
Introducing Lazy Route Modules! (#10045)
In order to keep your application bundles small and support code-splitting of your routes, we've introduced a new
lazy()route property. This is an async function that resolves the non-route-matching portions of your route definition (loader,action,element/Component,errorElement/ErrorBoundary,shouldRevalidate,handle).Lazy routes are resolved on initial load and during the
loadingorsubmittingphase of a navigation or fetcher call. You cannot lazily define route-matching properties (path,index,children) since we only execute your lazy route functions after we've matched known routes.Your
lazyfunctions will typically return the result of a dynamic import.// In this example, we assume most folks land on the homepage so we include that // in our critical-path bundle, but then we lazily load modules for /a and /b so // they don't load until the user navigates to those routes let routes = createRoutesFromElements( <Route path="/" element={<Layout />}> <Route index element={<Home />} /> <Route path="a" lazy={() => import("./a")} /> <Route path="b" lazy={() => import("./b")} /> </Route> );Then in your lazy route modules, export the properties you want defined for the route:
export async function loader({ request }) { let data = await fetchData(request); return json(data); } // Export a `Component` directly instead of needing to create a React Element from it export function Component() { let data = useLoaderData(); return ( <> <h1>You made it!</h1> <p>{data}</p> </> ); } // Export an `ErrorBoundary` directly instead of needing to create a React Element from it export function ErrorBoundary() { let error = useRouteError(); return isRouteErrorResponse(error) ? ( <h1> {error.status} {error.statusText} </h1> ) : ( <h1>{error.message || error}</h1> ); }An example of this in action can be found in the
examples/lazy-loading-router-providerdirectory of the repository.🙌 Huge thanks to @rossipedia for the Initial Proposal and POC Implementation.
Patch Changes
- Fix
generatePathincorrectly applying parameters in some cases (#10078)
1.3.3
Patch Changes
- Correctly perform a hard redirect for same-origin absolute URLs outside of the router
basename(#10076) - Ensure status code and headers are maintained for
deferloader responses increateStaticHandler'squery()method (#10077) - Change
invariantto anUNSAFE_invariantexport since it's only intended for internal use (#10066) - Add internal API for custom HMR implementations (#9996)
1.3.2
Patch Changes
- Remove inaccurate console warning for POP navigations and update active blocker logic (#10030)
- Only check for differing origin on absolute URL redirects (#10033)
1.3.1
Patch Changes
- Fixes 2 separate issues for revalidating fetcher
shouldRevalidatecalls (#9948)- The
shouldRevalidatefunction was only being called for explicit revalidation scenarios (after a mutation, manualuseRevalidatorcall, or anX-Remix-Revalidateheader used for cookie setting in Remix). It was not properly being called on implicit revalidation scenarios that also apply to navigationloaderrevalidation, such as a change in search params or clicking a link for the page we're already on. It's now correctly called in those additional scenarios. - The parameters being passed were incorrect and inconsistent with one another since the
current*/next*parameters reflected the staticfetcher.loadURL (and thus were identical). Instead, they should have reflected the the navigation that triggered the revalidation (as theform*parameters did). These parameters now correctly reflect the triggering navigation.
- The
- Respect
preventScrollReseton<fetcher.Form>(#9963) - Do not short circuit on hash change only mutation submissions (#9944)
- Remove
instanceofcheck fromisRouteErrorResponseto avoid bundling issues on the server (#9930) - Fix navigation for hash routers on manual URL changes (#9980)
- Detect when a
defercall only contains critical data and remove theAbortController(#9965) - Send the name as the value when url-encoding
FileFormDataentries (#9867)
1.3.0
Minor Changes
- Added support for navigation blocking APIs (#9709)
- Expose deferred information from
createStaticHandler(#9760)
Patch Changes
- Improved absolute redirect url detection in actions/loaders (#9829)
- Fix URL creation with memory histories (#9814)
- Fix
generatePathwhen optional params are present (#9764) - Fix scroll reset if a submission redirects (#9886)
- Fix 404 bug with same-origin absolute redirects (#9913)
- Support
OPTIONSrequests instaticHandler.queryRoute(#9914)
1.2.1
Patch Changes
- Include submission info in
shouldRevalidateon action redirects (#9777, #9782) - Reset
actionDataon action redirect to current location (#9772)
1.2.0
Minor Changes
- Remove
unstable_prefix fromcreateStaticHandler/createStaticRouter/StaticRouterProvider(#9738)
Patch Changes
- Fix explicit
replaceon submissions andPUSHon submission to new paths (#9734) - Fix a few bugs where loader/action data wasn't properly cleared on errors (#9735)
- Prevent
useLoaderDatausage inerrorElement(#9735) - Skip initial scroll restoration for SSR apps with
hydrationData(#9664)
1.1.0
This release introduces support for Optional Route Segments. Now, adding a ? to the end of any path segment will make that entire segment optional. This works for both static segments and dynamic parameters.
Optional Params Examples
- Path
lang?/aboutwill match:/:lang/about/about
- Path
/multistep/:widget1?/widget2?/widget3?will match:/multistep/multistep/:widget1/multistep/:widget1/:widget2/multistep/:widget1/:widget2/:widget3
Optional Static Segment Example
- Path
/home?will match://home
- Path
/fr?/aboutwill match:/about/fr/about
Minor Changes
- Allows optional routes and optional static segments (#9650)
Patch Changes
- Stop incorrectly matching on partial named parameters, i.e.
<Route path="prefix-:param">, to align with how splat parameters work. If you were previously relying on this behavior then it's recommended to extract the static portion of the path at theuseParamscall site: (#9506)
// Old behavior at URL /prefix-123
<Route path="prefix-:id" element={<Comp /> }>
function Comp() {
let params = useParams(); // { id: '123' }
let id = params.id; // "123"
...
}
// New behavior at URL /prefix-123
<Route path=":id" element={<Comp /> }>
function Comp() {
let params = useParams(); // { id: 'prefix-123' }
let id = params.id.replace(/^prefix-/, ''); // "123"
...
}
- Persist
headersonloaderrequest's after SSR documentactionrequest (#9721) - Fix requests sent to revalidating loaders so they reflect a GET request (#9660)
- Fix issue with deeply nested optional segments (#9727)
- GET forms now expose a submission on the loading navigation (#9695)
- Fix error boundary tracking for multiple errors bubbling to the same boundary (#9702)
1.0.5
Patch Changes
- Fix requests sent to revalidating loaders so they reflect a
GETrequest (#9680) - Remove
instanceof Responsechecks in favor ofisResponse(#9690) - Fix
URLcreation in Cloudflare Pages or other non-browser-environments (#9682, #9689) - Add
requestContextsupport to static handlerquery/queryRoute(#9696)- Note that the unstable API of
queryRoute(path, routeId)has been changed toqueryRoute(path, { routeId, requestContext })
- Note that the unstable API of
1.0.4
Patch Changes
- Throw an error if an
action/loaderfunction returnsundefinedas revalidations need to know whether the loader has previously been executed.undefinedalso causes issues during SSR stringification for hydration. You should always ensure youloader/actionreturns a value, and you may returnnullif you don't wish to return anything. (#9511) - Properly handle redirects to external domains (#9590, #9654)
- Preserve the HTTP method on 307/308 redirects (#9597)
- Support
basenamein static data routers (#9591) - Enhanced
ErrorResponsebodies to contain more descriptive text in internal 403/404/405 scenarios
1.0.3
Patch Changes
- Fix hrefs generated when using
createHashRouter(#9409) - fix encoding/matching issues with special chars (#9477, #9496)
- Support
basenameand relative routing inloader/actionredirects (#9447) - Ignore pathless layout routes when looking for proper submission
actionfunction (#9455) - properly support
indexroutes with apathinuseResolvedPath(#9486) - Add UMD build for
@remix-run/router(#9446) - fix
createURLin local file execution in Firefox (#9464) - Updates to
unstable_createStaticHandlerfor incorporating into Remix (#9482, #9465)
1.0.2
Patch Changes
- Reset
actionDataafter a successful action redirect (#9334) - Update
matchPathto avoid false positives on dash-separated segments (#9300) - If an index route has children, it will result in a runtime error. We have strengthened our
RouteObject/RoutePropstypes to surface the error in TypeScript. (#9366)
1.0.1
Patch Changes
- Preserve state from
initialEntries(#9288) - Preserve
?indexfor fetcher get submissions to index routes (#9312)
1.0.0
This is the first stable release of @remix-run/router, which provides all the underlying routing and data loading/mutation logic for react-router. You should not be using this package directly unless you are authoring a routing library similar to react-router.
For an overview of the features provided by react-router, we recommend you go check out the docs, especially the feature overview and the tutorial.
For an overview of the features provided by @remix-run/router, please check out the README.