Skip to content

Commit

Permalink
seed prefetch cache with initial page
Browse files Browse the repository at this point in the history
  • Loading branch information
ztanner committed Feb 6, 2024
1 parent 0fb8a34 commit 508f8a5
Show file tree
Hide file tree
Showing 13 changed files with 492 additions and 111 deletions.
12 changes: 10 additions & 2 deletions packages/next/src/client/components/app-router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ function Router({
initialTree,
initialCanonicalUrl,
initialSeedData,
initialFlightData,
assetPrefix,
missingSlots,
}: AppRouterProps) {
Expand All @@ -275,11 +276,18 @@ function Router({
initialCanonicalUrl,
initialTree,
initialParallelRoutes,
isServer,
location: !isServer ? window.location : null,
initialHead,
initialFlightData,
}),
[buildId, initialSeedData, initialCanonicalUrl, initialTree, initialHead]
[
buildId,
initialSeedData,
initialCanonicalUrl,
initialTree,
initialHead,
initialFlightData,
]
)
const [reducerState, dispatch, sync] =
useReducerWithReduxDevtools(initialState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react'
import type { FlightRouterState } from '../../../server/app-render/types'
import type { CacheNode } from '../../../shared/lib/app-router-context.shared-runtime'
import { createInitialRouterState } from './create-initial-router-state'
import { PrefetchKind } from './router-reducer-types'

const buildId = 'development'

Expand Down Expand Up @@ -37,8 +38,8 @@ describe('createInitialRouterState', () => {
initialTree,
initialCanonicalUrl,
initialSeedData: ['', {}, children],
initialFlightData: [['']],
initialParallelRoutes,
isServer: false,
location: new URL('/linking', 'https://localhost') as any,
initialHead: <title>Test</title>,
})
Expand All @@ -48,8 +49,8 @@ describe('createInitialRouterState', () => {
initialTree,
initialCanonicalUrl,
initialSeedData: ['', {}, children],
initialFlightData: [['']],
initialParallelRoutes,
isServer: false,
location: new URL('/linking', 'https://localhost') as any,
initialHead: <title>Test</title>,
})
Expand Down Expand Up @@ -96,7 +97,19 @@ describe('createInitialRouterState', () => {
buildId,
tree: initialTree,
canonicalUrl: initialCanonicalUrl,
prefetchCache: new Map(),
prefetchCache: new Map([
[
'/linking',
{
key: '/linking',
data: expect.any(Promise),
prefetchTime: expect.any(Number),
kind: PrefetchKind.AUTO,
lastUsedTime: null,
treeAtTimeOfPrefetch: initialTree,
},
],
]),
pushRef: {
pendingPush: false,
mpaNavigation: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ import type { CacheNode } from '../../../shared/lib/app-router-context.shared-ru
import type {
FlightRouterState,
CacheNodeSeedData,
FlightData,
} from '../../../server/app-render/types'

import { createHrefFromUrl } from './create-href-from-url'
import { fillLazyItemsTillLeafWithHead } from './fill-lazy-items-till-leaf-with-head'
import { extractPathFromFlightRouterState } from './compute-changed-path'
import { createPrefetchCacheKey } from './reducers/prefetch-cache-utils'
import { PrefetchKind, type PrefetchCacheEntry } from './router-reducer-types'

export interface InitialRouterStateParameters {
buildId: string
initialTree: FlightRouterState
initialCanonicalUrl: string
initialSeedData: CacheNodeSeedData
initialParallelRoutes: CacheNode['parallelRoutes']
isServer: boolean
initialFlightData: FlightData
location: Location | null
initialHead: ReactNode
}
Expand All @@ -26,10 +29,11 @@ export function createInitialRouterState({
initialSeedData,
initialCanonicalUrl,
initialParallelRoutes,
isServer,
initialFlightData,
location,
initialHead,
}: InitialRouterStateParameters) {
const isServer = !location
const rsc = initialSeedData[2]

const cache: CacheNode = {
Expand All @@ -40,6 +44,25 @@ export function createInitialRouterState({
parallelRoutes: isServer ? new Map() : initialParallelRoutes,
}

const prefetchCache = new Map<string, PrefetchCacheEntry>()

if (location && initialFlightData.length > 0) {
// Seed the prefetch cache with this page's data.
// This is to prevent needlessly re-prefetching a page that is already reusable,
// and will avoid triggering a loading state/data fetch stall when navigating back to the page.
const url = new URL(location.pathname, location.origin)
const cacheKey = createPrefetchCacheKey(url)

prefetchCache.set(cacheKey, {
data: Promise.resolve([initialFlightData, undefined, false, false]),
kind: PrefetchKind.AUTO,
lastUsedTime: null,
prefetchTime: Date.now(),
key: cacheKey,
treeAtTimeOfPrefetch: initialTree,
})
}

// When the cache hasn't been seeded yet we fill the cache with the head.
if (initialParallelRoutes === null || initialParallelRoutes.size === 0) {
fillLazyItemsTillLeafWithHead(
Expand All @@ -55,7 +78,7 @@ export function createInitialRouterState({
buildId,
tree: initialTree,
cache,
prefetchCache: new Map(),
prefetchCache,
pushRef: {
pendingPush: false,
mpaNavigation: false,
Expand Down
Loading

0 comments on commit 508f8a5

Please sign in to comment.