From 5c23cd3045e277c9c0a398059edc7dc8c308f816 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 12 Dec 2023 11:14:22 -0500 Subject: [PATCH] Add CacheNode.prefetchRsc field Adds a new field `prefetchRsc` to CacheNode that will be used by the PPR implementation. It represents a static version of the segment that can be showed immediately, and may or may not contain dynamic holes. It's prefetched before a navigation occurs. During rendering, we will choose whether to render `rsc` or `prefetchRsc` with `useDeferredValue`. As with the `rsc` field, a value of `null` means no value was provided. In this case, the LayoutRouter will go straight to rendering the `rsc` value; if that one is also missing, it will suspend and trigger a lazy fetch. The non-PPR implementation will never set this value. This PR adds the field to the CacheNode type but doesn't implement any of the behavior yet. Mostly this involves updating the router reducer unit tests. --- .../next/src/client/components/app-router.tsx | 13 ++++++---- .../src/client/components/layout-router.tsx | 4 ++++ .../router-reducer/apply-flight-data.ts | 10 ++++++++ .../create-initial-router-state.test.tsx | 3 +++ .../create-initial-router-state.ts | 1 + .../fill-cache-with-data-property.test.tsx | 4 ++++ .../fill-cache-with-data-property.ts | 3 +++ .../fill-cache-with-new-subtree-data.test.tsx | 9 +++++++ .../fill-cache-with-new-subtree-data.ts | 2 ++ ...ll-lazy-items-till-leaf-with-head.test.tsx | 9 +++++++ .../fill-lazy-items-till-leaf-with-head.ts | 13 ++++++++++ ...te-cache-below-flight-segmentpath.test.tsx | 8 +++++++ ...validate-cache-below-flight-segmentpath.ts | 1 + .../invalidate-cache-by-router-state.test.tsx | 5 ++++ .../reducers/find-head-in-cache.test.tsx | 5 ++++ .../reducers/navigate-reducer.test.tsx | 20 ++++++++++++++++ .../reducers/navigate-reducer.ts | 2 ++ .../reducers/prefetch-reducer.test.tsx | 6 +++++ .../reducers/refresh-reducer.test.tsx | 24 +++++++++++++++++++ .../reducers/refresh-reducer.ts | 1 + .../reducers/restore-reducer.test.tsx | 10 ++++++++ .../reducers/server-action-reducer.ts | 1 + .../reducers/server-patch-reducer.test.tsx | 4 ++++ .../lib/app-router-context.shared-runtime.ts | 6 ++--- 24 files changed, 155 insertions(+), 9 deletions(-) diff --git a/packages/next/src/client/components/app-router.tsx b/packages/next/src/client/components/app-router.tsx index 1c17ad40e9be0..c9cf9c077403e 100644 --- a/packages/next/src/client/components/app-router.tsx +++ b/packages/next/src/client/components/app-router.tsx @@ -147,11 +147,14 @@ function HistoryUpdater({ return null } -export const createEmptyCacheNode = () => ({ - lazyData: null, - rsc: null, - parallelRoutes: new Map(), -}) +export function createEmptyCacheNode(): CacheNode { + return { + lazyData: null, + rsc: null, + prefetchRsc: null, + parallelRoutes: new Map(), + } +} function useServerActionDispatcher(dispatch: React.Dispatch) { const serverActionDispatcher: ServerActionDispatcher = useCallback( diff --git a/packages/next/src/client/components/layout-router.tsx b/packages/next/src/client/components/layout-router.tsx index 109ffa68c8e6a..f30c349b7c393 100644 --- a/packages/next/src/client/components/layout-router.tsx +++ b/packages/next/src/client/components/layout-router.tsx @@ -353,6 +353,9 @@ function InnerLayoutRouter({ // TODO-APP: remove '' const refetchTree = walkAddRefetch(['', ...segmentPath], fullTree) + // TODO: Since this case always suspends indefinitely, and the only thing + // we're doing here is setting `lazyData`, it would be fine to mutate the + // current cache node (if it exists) rather than cloning it. childNode = { lazyData: fetchServerResponse( new URL(url, location.origin), @@ -361,6 +364,7 @@ function InnerLayoutRouter({ buildId ), rsc: null, + prefetchRsc: childNode ? childNode.prefetchRsc : null, head: childNode ? childNode.head : undefined, parallelRoutes: childNode ? childNode.parallelRoutes : new Map(), } diff --git a/packages/next/src/client/components/router-reducer/apply-flight-data.ts b/packages/next/src/client/components/router-reducer/apply-flight-data.ts index fabf4132c40e5..5003f47cbf5cf 100644 --- a/packages/next/src/client/components/router-reducer/apply-flight-data.ts +++ b/packages/next/src/client/components/router-reducer/apply-flight-data.ts @@ -20,6 +20,12 @@ export function applyFlightData( if (flightDataPath.length === 3) { const rsc = cacheNodeSeedData[2] cache.rsc = rsc + // This is a PPR-only field. When PPR is enabled, we shouldn't hit + // this path during a navigation, but until PPR is fully implemented + // yet it's possible the existing node does have a non-null + // `prefetchRsc`. As an incremental step, we'll just de-opt to the + // old behavior — no PPR value. + cache.prefetchRsc = null fillLazyItemsTillLeafWithHead( cache, existingCache, @@ -31,6 +37,10 @@ export function applyFlightData( } else { // Copy rsc for the root node of the cache. cache.rsc = existingCache.rsc + // This is a PPR-only field. Unlike the previous branch, since we're + // just cloning the existing cache node, we might as well keep the + // PPR value, if it exists. + cache.prefetchRsc = existingCache.prefetchRsc cache.parallelRoutes = new Map(existingCache.parallelRoutes) // Create a copy of the existing cache with the rsc applied. fillCacheWithNewSubTreeData( diff --git a/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx b/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx index 63e404383a68b..48067db2c07a6 100644 --- a/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx +++ b/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx @@ -57,6 +57,7 @@ describe('createInitialRouterState', () => { const expectedCache: CacheNode = { lazyData: null, rsc: children, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -73,6 +74,7 @@ describe('createInitialRouterState', () => { { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), head: Test, }, @@ -82,6 +84,7 @@ describe('createInitialRouterState', () => { ]), lazyData: null, rsc: null, + prefetchRsc: null, }, ], ]), diff --git a/packages/next/src/client/components/router-reducer/create-initial-router-state.ts b/packages/next/src/client/components/router-reducer/create-initial-router-state.ts index 66ac0f2f6f7a6..deaca80dc00ff 100644 --- a/packages/next/src/client/components/router-reducer/create-initial-router-state.ts +++ b/packages/next/src/client/components/router-reducer/create-initial-router-state.ts @@ -35,6 +35,7 @@ export function createInitialRouterState({ const cache: CacheNode = { lazyData: null, rsc: rsc, + prefetchRsc: null, // The cache gets seeded during the first render. `initialParallelRoutes` ensures the cache from the first render is there during the second render. parallelRoutes: isServer ? new Map() : initialParallelRoutes, } diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx index 8efbba3505d5c..9a492c0f8bde5 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx @@ -24,11 +24,13 @@ describe('fillCacheWithDataProperty', () => { const cache: CacheNode = { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), } const existingCache: CacheNode = { lazyData: null, rsc: <>Root layout, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -38,6 +40,7 @@ describe('fillCacheWithDataProperty', () => { { lazyData: null, rsc: <>Linking, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -47,6 +50,7 @@ describe('fillCacheWithDataProperty', () => { { lazyData: null, rsc: <>Page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts index af39cbb533cd5..98c247b6d2053 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts @@ -40,6 +40,7 @@ export function fillCacheWithDataProperty( childSegmentMap.set(cacheKey, { lazyData: fetchResponse(), rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), }) } @@ -52,6 +53,7 @@ export function fillCacheWithDataProperty( childSegmentMap.set(cacheKey, { lazyData: fetchResponse(), rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), }) } @@ -62,6 +64,7 @@ export function fillCacheWithDataProperty( childCacheNode = { lazyData: childCacheNode.lazyData, rsc: childCacheNode.rsc, + prefetchRsc: childCacheNode.prefetchRsc, parallelRoutes: new Map(childCacheNode.parallelRoutes), } as CacheNode childSegmentMap.set(cacheKey, childCacheNode) diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx index a331760b92444..6cf7cf2bc608a 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx @@ -29,11 +29,13 @@ describe('fillCacheWithNewSubtreeData', () => { const cache: CacheNode = { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), } const existingCache: CacheNode = { lazyData: null, rsc: <>Root layout, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -43,6 +45,7 @@ describe('fillCacheWithNewSubtreeData', () => { { lazyData: null, rsc: <>Linking, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -52,6 +55,7 @@ describe('fillCacheWithNewSubtreeData', () => { { lazyData: null, rsc: <>Page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -79,6 +83,7 @@ describe('fillCacheWithNewSubtreeData', () => { const expectedCache: CacheNode = { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -88,6 +93,7 @@ describe('fillCacheWithNewSubtreeData', () => { { lazyData: null, rsc: <>Linking, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -98,6 +104,7 @@ describe('fillCacheWithNewSubtreeData', () => { { lazyData: null, rsc: <>Page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -114,6 +121,7 @@ describe('fillCacheWithNewSubtreeData', () => { { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), head: ( <> @@ -126,6 +134,7 @@ describe('fillCacheWithNewSubtreeData', () => { ], ]), rsc:

SubTreeData Injected!

, + prefetchRsc: null, }, ], ]), diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts index 67bd53b1a9495..78768ad778d94 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts @@ -50,6 +50,7 @@ export function fillCacheWithNewSubTreeData( childCacheNode = { lazyData: null, rsc, + prefetchRsc: null, // Ensure segments other than the one we got data for are preserved. parallelRoutes: existingChildCacheNode ? new Map(existingChildCacheNode.parallelRoutes) @@ -88,6 +89,7 @@ export function fillCacheWithNewSubTreeData( childCacheNode = { lazyData: childCacheNode.lazyData, rsc: childCacheNode.rsc, + prefetchRsc: childCacheNode.prefetchRsc, parallelRoutes: new Map(childCacheNode.parallelRoutes), } as CacheNode childSegmentMap.set(cacheKey, childCacheNode) diff --git a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx index 28b075a069d75..c8b22c5539ed8 100644 --- a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx +++ b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx @@ -38,11 +38,13 @@ describe('fillLazyItemsTillLeafWithHead', () => { const cache: CacheNode = { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), } const existingCache: CacheNode = { lazyData: null, rsc: <>Root layout, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -52,6 +54,7 @@ describe('fillLazyItemsTillLeafWithHead', () => { { lazyData: null, rsc: <>Linking, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -61,6 +64,7 @@ describe('fillLazyItemsTillLeafWithHead', () => { { lazyData: null, rsc: <>Page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -94,6 +98,7 @@ describe('fillLazyItemsTillLeafWithHead', () => { const expectedCache: CacheNode = { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -103,6 +108,7 @@ describe('fillLazyItemsTillLeafWithHead', () => { { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -120,6 +126,7 @@ describe('fillLazyItemsTillLeafWithHead', () => { { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), head: ( <> @@ -132,6 +139,7 @@ describe('fillLazyItemsTillLeafWithHead', () => { ], ]), rsc: null, + prefetchRsc: null, }, ], [ @@ -139,6 +147,7 @@ describe('fillLazyItemsTillLeafWithHead', () => { { lazyData: null, rsc: <>Page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], diff --git a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts index 0b67e49f2c1e7..691ec50fa2ecc 100644 --- a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts +++ b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts @@ -53,6 +53,12 @@ export function fillLazyItemsTillLeafWithHead( newCacheNode = { lazyData: null, rsc: seedNode, + // This is a PPR-only field. When PPR is enabled, we shouldn't hit + // this path during a navigation, but until PPR is fully implemented + // yet it's possible the existing node does have a non-null + // `prefetchRsc`. As an incremental step, we'll just de-opt to the + // old behavior — no PPR value. + prefetchRsc: null, parallelRoutes: new Map(existingCacheNode?.parallelRoutes), } } else if (wasPrefetched && existingCacheNode) { @@ -61,6 +67,10 @@ export function fillLazyItemsTillLeafWithHead( newCacheNode = { lazyData: existingCacheNode.lazyData, rsc: existingCacheNode.rsc, + // This is a PPR-only field. Unlike the previous branch, since we're + // just cloning the existing cache node, we might as well keep the + // PPR value, if it exists. + prefetchRsc: existingCacheNode.prefetchRsc, parallelRoutes: new Map(existingCacheNode.parallelRoutes), } as CacheNode } else { @@ -69,6 +79,7 @@ export function fillLazyItemsTillLeafWithHead( newCacheNode = { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(existingCacheNode?.parallelRoutes), } } @@ -97,6 +108,7 @@ export function fillLazyItemsTillLeafWithHead( newCacheNode = { lazyData: null, rsc: seedNode, + prefetchRsc: null, parallelRoutes: new Map(), } } else { @@ -105,6 +117,7 @@ export function fillLazyItemsTillLeafWithHead( newCacheNode = { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), } } diff --git a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx index 9589560548657..4b175010b7637 100644 --- a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx +++ b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx @@ -30,11 +30,13 @@ describe('invalidateCacheBelowFlightSegmentPath', () => { const cache: CacheNode = { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), } const existingCache: CacheNode = { lazyData: null, rsc: <>Root layout, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -44,6 +46,7 @@ describe('invalidateCacheBelowFlightSegmentPath', () => { { lazyData: null, rsc: <>Linking, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -53,6 +56,7 @@ describe('invalidateCacheBelowFlightSegmentPath', () => { { lazyData: null, rsc: <>Page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -78,6 +82,7 @@ describe('invalidateCacheBelowFlightSegmentPath', () => { // Copy rsc for the root node of the cache. cache.rsc = existingCache.rsc + cache.prefetchRsc = existingCache.prefetchRsc // Create a copy of the existing cache with the rsc applied. fillCacheWithNewSubTreeData(cache, existingCache, flightDataPath, false) @@ -108,18 +113,21 @@ describe('invalidateCacheBelowFlightSegmentPath', () => { lazyData: null, parallelRoutes: new Map(), rsc: Page, + prefetchRsc: null, }, ], ]), ], ]), rsc: Linking, + prefetchRsc: null, }, ], ]), ], ]), rsc: <>Root layout, + prefetchRsc: null, } expect(cache).toMatchObject(expectedCache) diff --git a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts index 4463189588baa..1f530701a35f6 100644 --- a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts +++ b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts @@ -49,6 +49,7 @@ export function invalidateCacheBelowFlightSegmentPath( childCacheNode = { lazyData: childCacheNode.lazyData, rsc: childCacheNode.rsc, + prefetchRsc: childCacheNode.prefetchRsc, parallelRoutes: new Map(childCacheNode.parallelRoutes), } as CacheNode childSegmentMap.set(cacheKey, childCacheNode) diff --git a/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx b/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx index d18c0c67185ae..06cdaff97aa65 100644 --- a/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx +++ b/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx @@ -8,11 +8,13 @@ describe('invalidateCacheByRouterState', () => { const cache: CacheNode = { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), } const existingCache: CacheNode = { lazyData: null, rsc: <>Root layout, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -22,6 +24,7 @@ describe('invalidateCacheByRouterState', () => { { lazyData: null, rsc: <>Linking, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -31,6 +34,7 @@ describe('invalidateCacheByRouterState', () => { { lazyData: null, rsc: <>Page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -69,6 +73,7 @@ describe('invalidateCacheByRouterState', () => { const expectedCache: CacheNode = { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map([['children', new Map()]]), } diff --git a/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx b/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx index 2415c1a3a858a..89be65c4265e9 100644 --- a/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx @@ -28,6 +28,7 @@ describe('findHeadInCache', () => { const cache: CacheNode = { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -37,6 +38,7 @@ describe('findHeadInCache', () => { { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -54,6 +56,7 @@ describe('findHeadInCache', () => { { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), head: ( <> @@ -66,6 +69,7 @@ describe('findHeadInCache', () => { ], ]), rsc: null, + prefetchRsc: null, }, ], // TODO-APP: this segment should be preserved when creating the new cache @@ -74,6 +78,7 @@ describe('findHeadInCache', () => { // { // lazyData: null, // rsc: <>Page, + // prefetchRsc: null, // parallelRoutes: new Map(), // }, // ], diff --git a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx index 4cfaa97aae6d8..a59d77ef0921d 100644 --- a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx @@ -141,6 +141,7 @@ describe('navigateReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -149,6 +150,7 @@ describe('navigateReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -327,6 +329,7 @@ describe('navigateReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -335,6 +338,7 @@ describe('navigateReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -514,6 +518,7 @@ describe('navigateReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -522,6 +527,7 @@ describe('navigateReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -646,6 +652,7 @@ describe('navigateReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -654,6 +661,7 @@ describe('navigateReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -778,6 +786,7 @@ describe('navigateReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -786,6 +795,7 @@ describe('navigateReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -931,6 +941,7 @@ describe('navigateReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -939,6 +950,7 @@ describe('navigateReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -1171,6 +1183,7 @@ describe('navigateReducer', () => { { lazyData: null, rsc: <>Audience Page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -1184,6 +1197,7 @@ describe('navigateReducer', () => { { lazyData: null, rsc: <>Views Page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -1197,6 +1211,7 @@ describe('navigateReducer', () => { { lazyData: null, rsc: <>Children Page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -1205,6 +1220,7 @@ describe('navigateReducer', () => { ]), lazyData: null, rsc: <>Layout level, + prefetchRsc: null, }, ], ]), @@ -1414,6 +1430,7 @@ describe('navigateReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -1422,6 +1439,7 @@ describe('navigateReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -1543,6 +1561,7 @@ describe('navigateReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -1551,6 +1570,7 @@ describe('navigateReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), diff --git a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts index 3ad4ace451ca8..e12e50c3a297a 100644 --- a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts @@ -78,6 +78,7 @@ function addRefetchToLeafSegments( let appliedPatch = false newCache.rsc = currentCache.rsc + newCache.prefetchRsc = currentCache.prefetchRsc newCache.parallelRoutes = new Map(currentCache.parallelRoutes) const segmentPathsToFill = generateSegmentsFromPatch(treePatch).map( @@ -239,6 +240,7 @@ export function navigateReducer( if (hardNavigate) { // Copy rsc for the root node of the cache. cache.rsc = currentCache.rsc + cache.prefetchRsc = currentCache.prefetchRsc invalidateCacheBelowFlightSegmentPath( cache, diff --git a/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx index 05f660c0d4897..e147c9e3346db 100644 --- a/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx @@ -95,6 +95,7 @@ describe('prefetchReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -103,6 +104,7 @@ describe('prefetchReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -187,6 +189,7 @@ describe('prefetchReducer', () => { Root layout ), + prefetchRsc: null, parallelRoutes: initialParallelRoutes, }, tree: [ @@ -234,6 +237,7 @@ describe('prefetchReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -242,6 +246,7 @@ describe('prefetchReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -340,6 +345,7 @@ describe('prefetchReducer', () => { Root layout ), + prefetchRsc: null, parallelRoutes: initialParallelRoutes, }, tree: [ diff --git a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx index 5e302a911b4bc..f7909760d7c59 100644 --- a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx @@ -106,6 +106,7 @@ describe('refreshReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -114,6 +115,7 @@ describe('refreshReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -165,6 +167,7 @@ describe('refreshReducer', () => { ), + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -181,6 +184,7 @@ describe('refreshReducer', () => { { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), head: ( <> @@ -194,6 +198,7 @@ describe('refreshReducer', () => { ]), lazyData: null, rsc: null, + prefetchRsc: null, }, ], ]), @@ -244,6 +249,7 @@ describe('refreshReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -252,6 +258,7 @@ describe('refreshReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -317,6 +324,7 @@ describe('refreshReducer', () => { ), + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -333,6 +341,7 @@ describe('refreshReducer', () => { { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), head: ( <> @@ -346,6 +355,7 @@ describe('refreshReducer', () => { ]), lazyData: null, rsc: null, + prefetchRsc: null, }, ], ]), @@ -396,6 +406,7 @@ describe('refreshReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -404,6 +415,7 @@ describe('refreshReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], [ @@ -418,6 +430,7 @@ describe('refreshReducer', () => { { lazyData: null, rsc: <>About page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -426,6 +439,7 @@ describe('refreshReducer', () => { ]), lazyData: null, rsc: <>About layout level, + prefetchRsc: null, }, ], ]), @@ -491,6 +505,7 @@ describe('refreshReducer', () => { ), + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -507,6 +522,7 @@ describe('refreshReducer', () => { { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), head: ( <> @@ -520,6 +536,7 @@ describe('refreshReducer', () => { ]), lazyData: null, rsc: null, + prefetchRsc: null, }, ], ]), @@ -570,6 +587,7 @@ describe('refreshReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -578,6 +596,7 @@ describe('refreshReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], [ @@ -592,6 +611,7 @@ describe('refreshReducer', () => { { lazyData: null, rsc: <>About page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -600,6 +620,7 @@ describe('refreshReducer', () => { ]), lazyData: null, rsc: <>About layout level, + prefetchRsc: null, }, ], ]), @@ -714,6 +735,7 @@ describe('refreshReducer', () => { ), + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -730,6 +752,7 @@ describe('refreshReducer', () => { { lazyData: null, rsc: null, + prefetchRsc: null, parallelRoutes: new Map(), head: ( <> @@ -743,6 +766,7 @@ describe('refreshReducer', () => { ]), lazyData: null, rsc: null, + prefetchRsc: null, }, ], ]), diff --git a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts index 01a32295f6955..ed496f280b0b9 100644 --- a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts @@ -96,6 +96,7 @@ export function refreshReducer( if (cacheNodeSeedData !== null) { const rsc = cacheNodeSeedData[2] cache.rsc = rsc + cache.prefetchRsc = null fillLazyItemsTillLeafWithHead( cache, // Existing cache is not passed in as `router.refresh()` has to invalidate the entire cache. diff --git a/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx index da60183dcf379..b8c7f0dd78e4b 100644 --- a/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx @@ -62,6 +62,7 @@ describe('serverPatchReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -70,6 +71,7 @@ describe('serverPatchReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -138,6 +140,7 @@ describe('serverPatchReducer', () => { Root layout ), + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -154,6 +157,7 @@ describe('serverPatchReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -162,6 +166,7 @@ describe('serverPatchReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -212,6 +217,7 @@ describe('serverPatchReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -220,6 +226,7 @@ describe('serverPatchReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -301,6 +308,7 @@ describe('serverPatchReducer', () => { Root layout ), + prefetchRsc: null, parallelRoutes: new Map([ [ 'children', @@ -317,6 +325,7 @@ describe('serverPatchReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -325,6 +334,7 @@ describe('serverPatchReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), diff --git a/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts index f58a3b5025222..ff9d618405710 100644 --- a/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts @@ -244,6 +244,7 @@ export function serverActionReducer( if (rsc !== null) { const cache: CacheNode = createEmptyCacheNode() cache.rsc = rsc + cache.prefetchRsc = null fillLazyItemsTillLeafWithHead( cache, // Existing cache is not passed in as `router.refresh()` has to invalidate the entire cache. diff --git a/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx index 68ed42456e975..3ed90be2bc20d 100644 --- a/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx @@ -113,6 +113,7 @@ describe('serverPatchReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -121,6 +122,7 @@ describe('serverPatchReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), @@ -277,6 +279,7 @@ describe('serverPatchReducer', () => { { lazyData: null, rsc: <>Linking page, + prefetchRsc: null, parallelRoutes: new Map(), }, ], @@ -285,6 +288,7 @@ describe('serverPatchReducer', () => { ]), lazyData: null, rsc: <>Linking layout level, + prefetchRsc: null, }, ], ]), diff --git a/packages/next/src/shared/lib/app-router-context.shared-runtime.ts b/packages/next/src/shared/lib/app-router-context.shared-runtime.ts index 43ea6c434e845..467cb798482ea 100644 --- a/packages/next/src/shared/lib/app-router-context.shared-runtime.ts +++ b/packages/next/src/shared/lib/app-router-context.shared-runtime.ts @@ -31,8 +31,7 @@ export type LazyCacheNode = { */ rsc: null - // TODO: Add prefetchRsc field. - // prefetchRsc: null + prefetchRsc: React.ReactNode /** * A pending response for the lazy data fetch. If this is not present @@ -61,8 +60,7 @@ export type ReadyCacheNode = { */ rsc: React.ReactNode - // TODO: Add prefetchRsc field. - // prefetchRsc: React.ReactNode + prefetchRsc: React.ReactNode /** * There should never be a lazy data request in this case.