From de4bc2d7621d409c0c44bef02edca07f013ff627 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Mon, 9 Sep 2024 14:35:59 -0400 Subject: [PATCH] Stabilize unstable_patchRoutesOnNavigation --- .changeset/warm-melons-shop.md | 5 + .../__tests__/dom/partial-hydration-test.tsx | 4 +- .../__tests__/router/lazy-discovery-test.ts | 94 +++++++++---------- packages/react-router/index.ts | 2 +- packages/react-router/lib/components.tsx | 4 +- .../lib/dom-export/hydrated-router.tsx | 2 +- packages/react-router/lib/dom/lib.tsx | 6 +- packages/react-router/lib/router/router.ts | 6 +- 8 files changed, 64 insertions(+), 59 deletions(-) create mode 100644 .changeset/warm-melons-shop.md diff --git a/.changeset/warm-melons-shop.md b/.changeset/warm-melons-shop.md new file mode 100644 index 0000000000..4d73f59df9 --- /dev/null +++ b/.changeset/warm-melons-shop.md @@ -0,0 +1,5 @@ +--- +"react-router": minor +--- + +Stabilize `unstable_patchRoutesOnNavigation` diff --git a/packages/react-router/__tests__/dom/partial-hydration-test.tsx b/packages/react-router/__tests__/dom/partial-hydration-test.tsx index dbd6926f20..27fafc232e 100644 --- a/packages/react-router/__tests__/dom/partial-hydration-test.tsx +++ b/packages/react-router/__tests__/dom/partial-hydration-test.tsx @@ -70,7 +70,7 @@ describe("Partial Hydration Behavior", () => { future: { v7_partialHydration: true, }, - unstable_patchRoutesOnNavigation({ path, patch }) { + patchRoutesOnNavigation({ path, patch }) { if (path === "/parent/child") { patch("parent", [ { @@ -158,7 +158,7 @@ describe("Partial Hydration Behavior", () => { future: { v7_partialHydration: true, }, - unstable_patchRoutesOnNavigation({ path, patch }) { + patchRoutesOnNavigation({ path, patch }) { if (path === "/parent/child") { patch("parent", [ { diff --git a/packages/react-router/__tests__/router/lazy-discovery-test.ts b/packages/react-router/__tests__/router/lazy-discovery-test.ts index 03e45e9092..93d4327674 100644 --- a/packages/react-router/__tests__/router/lazy-discovery-test.ts +++ b/packages/react-router/__tests__/router/lazy-discovery-test.ts @@ -36,7 +36,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { loader: () => loaderDfd.promise, }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { let children = await childrenDfd.promise; patch("parent", children); }, @@ -92,7 +92,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ patch, matches }) { + async patchRoutesOnNavigation({ patch, matches }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -148,7 +148,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { loader: () => loaderDfd.promise, }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { let children = await childrenDfd.promise; patch("parent", children); }, @@ -222,7 +222,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ patch, matches }) { + async patchRoutesOnNavigation({ patch, matches }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -286,7 +286,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ path, matches, patch }) { + async patchRoutesOnNavigation({ path, matches, patch }) { let routeId = last(matches).route.id; calls.push([path, routeId]); patch("a", await aDfd.promise); @@ -341,7 +341,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ path, matches, patch }) { + async patchRoutesOnNavigation({ path, matches, patch }) { let routeId = last(matches).route.id; if (!path) { return; @@ -444,7 +444,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { }, }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { let leafRoute = last(matches).route; patch(leafRoute.id, await leafRoute.handle.loadChildren?.()); }, @@ -474,7 +474,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -522,7 +522,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "/:slug", }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { await tick(); patch(null, [ { @@ -550,7 +550,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "/product/:slug", }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { await tick(); patch(null, [ { @@ -584,7 +584,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { ], }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { await tick(); patch("product", [ { @@ -615,7 +615,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "/:slug", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); }, }); @@ -641,7 +641,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -671,7 +671,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "/splat/*", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); patch(null, [ { @@ -705,7 +705,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { ], }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { await tick(); patch("product", [ { @@ -740,7 +740,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -758,7 +758,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { expect(router.state.matches.map((m) => m.route.id)).toEqual(["splat"]); }); - it("recurses unstable_patchRoutesOnNavigation until a match is found", async () => { + it("recurses patchRoutesOnNavigation until a match is found", async () => { let count = 0; router = createRouter({ history: createMemoryHistory(), @@ -771,7 +771,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); count++; if (last(matches).route.id === "a") { @@ -819,7 +819,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { loader: () => loaderDfd.promise, }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { let children = await childrenDfd.promise; patch("parent", children); }, @@ -870,7 +870,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "*", }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { let children = await childrenDfd.promise; patch(null, children); }, @@ -908,7 +908,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { splat: "SPLAT 1", }, }, - async unstable_patchRoutesOnNavigation() { + async patchRoutesOnNavigation() { throw new Error("Should not be called"); }, }); @@ -935,7 +935,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "/parent", }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { patch(null, await childrenDfd.promise); }, }); @@ -986,7 +986,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "/:param", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { // We matched for the param but we want to patch in under root expect(matches.length).toBe(1); expect(matches[0].route.id).toBe("param"); @@ -1041,7 +1041,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "*", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { // We matched for the splat but we want to patch in at the top expect(matches.length).toBe(1); expect(matches[0].route.id).toBe("splat"); @@ -1091,7 +1091,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "/nope", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { expect(matches.length).toBe(0); let children = await childrenDfd.promise; patch(null, children); @@ -1142,7 +1142,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "parent", }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { let children = await childrenDfd.promise; patch("parent", children); }, @@ -1215,7 +1215,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: ":param", }, ], - async unstable_patchRoutesOnNavigation() { + async patchRoutesOnNavigation() { count++; await tick(); // Nothing to patch - there is no better static route in this case @@ -1251,7 +1251,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "static", }, ], - async unstable_patchRoutesOnNavigation() { + async patchRoutesOnNavigation() { count++; }, }); @@ -1299,7 +1299,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: ":param", }, ], - async unstable_patchRoutesOnNavigation() { + async patchRoutesOnNavigation() { count++; // Nothing to patch - there is no better static route in this case }, @@ -1347,7 +1347,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "parent", }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { let children = await childrenDfd.promise; patch("parent", children); }, @@ -1402,7 +1402,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "parent", }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { let children = await childrenDfd.promise; patch("parent", children); }, @@ -1459,7 +1459,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -1512,7 +1512,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -1565,7 +1565,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -1617,7 +1617,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -1674,7 +1674,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -1731,7 +1731,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -1789,7 +1789,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { await tick(); if (shouldThrow) { shouldThrow = false; @@ -1817,7 +1817,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { 400, "Bad Request", new Error( - 'Unable to match URL "/a/b" - the `unstable_patchRoutesOnNavigation()` ' + + 'Unable to match URL "/a/b" - the `patchRoutesOnNavigation()` ' + "function threw the following error:\nError: broke!" ), true @@ -1861,7 +1861,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { await tick(); if (shouldThrow) { shouldThrow = false; @@ -1892,7 +1892,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { 400, "Bad Request", new Error( - 'Unable to match URL "/a/b" - the `unstable_patchRoutesOnNavigation()` ' + + 'Unable to match URL "/a/b" - the `patchRoutesOnNavigation()` ' + "function threw the following error:\nError: broke!" ), true @@ -1943,7 +1943,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { ], }, ], - async unstable_patchRoutesOnNavigation() { + async patchRoutesOnNavigation() { await tick(); throw new Error("broke!"); }, @@ -1970,7 +1970,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { "Bad Request", new Error( 'Unable to match URL "/parent/child/grandchild" - the ' + - "`unstable_patchRoutesOnNavigation()` function threw the following " + + "`patchRoutesOnNavigation()` function threw the following " + "error:\nError: broke!" ), true @@ -2000,7 +2000,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "parent", }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { let children = await childrenDfd.promise; patch("parent", children); }, @@ -2039,7 +2039,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ @@ -2087,7 +2087,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "parent", }, ], - async unstable_patchRoutesOnNavigation({ patch }) { + async patchRoutesOnNavigation({ patch }) { let children = await childrenDfd.promise; patch("parent", children); }, @@ -2129,7 +2129,7 @@ describe("Lazy Route Discovery (Fog of War)", () => { path: "a", }, ], - async unstable_patchRoutesOnNavigation({ matches, patch }) { + async patchRoutesOnNavigation({ matches, patch }) { await tick(); if (last(matches).route.id === "a") { patch("a", [ diff --git a/packages/react-router/index.ts b/packages/react-router/index.ts index 3c5e402b57..1cde18d67b 100644 --- a/packages/react-router/index.ts +++ b/packages/react-router/index.ts @@ -93,7 +93,7 @@ export type { RouterProps, RouterProviderProps, RoutesProps, - PatchRoutesOnNavigationFunction as unstable_PatchRoutesOnNavigationFunction, + PatchRoutesOnNavigationFunction as PatchRoutesOnNavigationFunction, } from "./lib/components"; export type { NavigateFunction } from "./lib/hooks"; export { diff --git a/packages/react-router/lib/components.tsx b/packages/react-router/lib/components.tsx index bae812fb35..2dddec9e40 100644 --- a/packages/react-router/lib/components.tsx +++ b/packages/react-router/lib/components.tsx @@ -145,7 +145,7 @@ export function createMemoryRouter( initialEntries?: InitialEntry[]; initialIndex?: number; unstable_dataStrategy?: DataStrategyFunction; - unstable_patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction; + patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction; } ): RemixRouter { return createRouter({ @@ -159,7 +159,7 @@ export function createMemoryRouter( routes, mapRouteProperties, unstable_dataStrategy: opts?.unstable_dataStrategy, - unstable_patchRoutesOnNavigation: opts?.unstable_patchRoutesOnNavigation, + patchRoutesOnNavigation: opts?.patchRoutesOnNavigation, }).initialize(); } diff --git a/packages/react-router/lib/dom-export/hydrated-router.tsx b/packages/react-router/lib/dom-export/hydrated-router.tsx index a022601686..bd7b072e5b 100644 --- a/packages/react-router/lib/dom-export/hydrated-router.tsx +++ b/packages/react-router/lib/dom-export/hydrated-router.tsx @@ -174,7 +174,7 @@ function createHydratedRouter(): RemixRouter { ssrInfo.routeModules, () => router ), - unstable_patchRoutesOnNavigation: getPatchRoutesOnNavigationFunction( + patchRoutesOnNavigation: getPatchRoutesOnNavigationFunction( ssrInfo.manifest, ssrInfo.routeModules, ssrInfo.context.isSpaMode, diff --git a/packages/react-router/lib/dom/lib.tsx b/packages/react-router/lib/dom/lib.tsx index cf236e65fa..c6a280b2f4 100644 --- a/packages/react-router/lib/dom/lib.tsx +++ b/packages/react-router/lib/dom/lib.tsx @@ -123,7 +123,7 @@ interface DOMRouterOpts { future?: Partial; hydrationData?: HydrationState; unstable_dataStrategy?: DataStrategyFunction; - unstable_patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction; + patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction; window?: Window; } @@ -142,7 +142,7 @@ export function createBrowserRouter( routes, mapRouteProperties, unstable_dataStrategy: opts?.unstable_dataStrategy, - unstable_patchRoutesOnNavigation: opts?.unstable_patchRoutesOnNavigation, + patchRoutesOnNavigation: opts?.patchRoutesOnNavigation, window: opts?.window, }).initialize(); } @@ -162,7 +162,7 @@ export function createHashRouter( routes, mapRouteProperties, unstable_dataStrategy: opts?.unstable_dataStrategy, - unstable_patchRoutesOnNavigation: opts?.unstable_patchRoutesOnNavigation, + patchRoutesOnNavigation: opts?.patchRoutesOnNavigation, window: opts?.window, }).initialize(); } diff --git a/packages/react-router/lib/router/router.ts b/packages/react-router/lib/router/router.ts index bb8eb711a7..202ae3090a 100644 --- a/packages/react-router/lib/router/router.ts +++ b/packages/react-router/lib/router/router.ts @@ -369,7 +369,7 @@ export interface RouterInit { future?: Partial; hydrationData?: HydrationState; window?: Window; - unstable_patchRoutesOnNavigation?: AgnosticPatchRoutesOnNavigationFunction; + patchRoutesOnNavigation?: AgnosticPatchRoutesOnNavigationFunction; unstable_dataStrategy?: DataStrategyFunction; } @@ -809,7 +809,7 @@ export function createRouter(init: RouterInit): Router { let inFlightDataRoutes: AgnosticDataRouteObject[] | undefined; let basename = init.basename || "/"; let dataStrategyImpl = init.unstable_dataStrategy || defaultDataStrategy; - let patchRoutesOnNavigationImpl = init.unstable_patchRoutesOnNavigation; + let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation; // Config driven behavior flags let future: FutureConfig = { @@ -5271,7 +5271,7 @@ function getInternalRouterError( statusText = "Bad Request"; if (type === "route-discovery") { errorMessage = - `Unable to match URL "${pathname}" - the \`unstable_patchRoutesOnNavigation()\` ` + + `Unable to match URL "${pathname}" - the \`patchRoutesOnNavigation()\` ` + `function threw the following error:\n${message}`; } else if (method && pathname && routeId) { errorMessage =