Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add experimental client router cache config #62856

Merged
merged 4 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/next/src/build/webpack/plugins/define-env-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ export function getDefineEnv({
'process.env.__NEXT_MIDDLEWARE_MATCHERS': middlewareMatchers ?? [],
'process.env.__NEXT_MANUAL_CLIENT_BASE_PATH':
config.experimental.manualClientBasePath ?? false,
'process.env.__NEXT_CLIENT_ROUTER_DYNAMIC_STALETIME': JSON.stringify(
isNaN(Number(config.experimental.staleTimes?.dynamic))
? 30 // 30 seconds
: config.experimental.staleTimes?.dynamic
),
'process.env.__NEXT_CLIENT_ROUTER_STATIC_STALETIME': JSON.stringify(
isNaN(Number(config.experimental.staleTimes?.static))
? 5 * 60 // 5 minutes
: config.experimental.staleTimes?.static
),
'process.env.__NEXT_CLIENT_ROUTER_FILTER_ENABLED':
config.experimental.clientRouterFilter ?? true,
'process.env.__NEXT_CLIENT_ROUTER_S_FILTER':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,31 +243,38 @@ export function prunePrefetchCache(
}
}

const FIVE_MINUTES = 5 * 60 * 1000
const THIRTY_SECONDS = 30 * 1000
// These values are set by `define-env-plugin` (based on `nextConfig.experimental.staleTimes`)
// and default to 5 minutes (static) / 30 seconds (dynamic)
const DYNAMIC_STALETIME_MS =
Number(process.env.__NEXT_CLIENT_ROUTER_DYNAMIC_STALETIME) * 1000

const STATIC_STALETIME_MS =
Number(process.env.__NEXT_CLIENT_ROUTER_STATIC_STALETIME) * 1000

function getPrefetchEntryCacheStatus({
kind,
prefetchTime,
lastUsedTime,
}: PrefetchCacheEntry): PrefetchCacheEntryStatus {
// if the cache entry was prefetched or read less than 30s ago, then we want to re-use it
if (Date.now() < (lastUsedTime ?? prefetchTime) + THIRTY_SECONDS) {
// We will re-use the cache entry data for up to the `dynamic` staletime window.
if (Date.now() < (lastUsedTime ?? prefetchTime) + DYNAMIC_STALETIME_MS) {
return lastUsedTime
? PrefetchCacheEntryStatus.reusable
: PrefetchCacheEntryStatus.fresh
}

// if the cache entry was prefetched less than 5 mins ago, then we want to re-use only the loading state
// For "auto" prefetching, we'll re-use only the loading boundary for up to `static` staletime window.
// A stale entry will only re-use the `loading` boundary, not the full data.
// This will trigger a "lazy fetch" for the full data.
if (kind === 'auto') {
if (Date.now() < prefetchTime + FIVE_MINUTES) {
if (Date.now() < prefetchTime + STATIC_STALETIME_MS) {
return PrefetchCacheEntryStatus.stale
}
}

// if the cache entry was prefetched less than 5 mins ago and was a "full" prefetch, then we want to re-use it "full
// for "full" prefetching, we'll re-use the cache entry data for up to `static` staletime window.
if (kind === 'full') {
if (Date.now() < prefetchTime + FIVE_MINUTES) {
if (Date.now() < prefetchTime + STATIC_STALETIME_MS) {
return PrefetchCacheEntryStatus.reusable
}
}
Expand Down
6 changes: 6 additions & 0 deletions packages/next/src/server/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,12 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
validator: z.string().optional(),
})
.optional(),
staleTimes: z
.object({
dynamic: z.number().optional(),
static: z.number().optional(),
})
.optional(),
clientRouterFilter: z.boolean().optional(),
clientRouterFilterRedirects: z.boolean().optional(),
clientRouterFilterAllowedRate: z.number().optional(),
Expand Down
14 changes: 14 additions & 0 deletions packages/next/src/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ export interface ExperimentalConfig {
strictNextHead?: boolean
clientRouterFilter?: boolean
clientRouterFilterRedirects?: boolean
/**
* This config can be used to override the cache behavior for the client router.
* These values indicate the time, in seconds, that the cache should be considered
* reusable. When the `prefetch` Link prop is left unspecified, this will use the `dynamic` value.
* When the `prefetch` Link prop is set to `true`, this will use the `static` value.
*/
staleTimes?: {
dynamic?: number
static?: number
}
// decimal for percent for possible false positives
// e.g. 0.01 for 10% potential false matches lower
// percent increases size of the filter
Expand Down Expand Up @@ -926,6 +936,10 @@ export const defaultConfig: NextConfig = {
missingSuspenseWithCSRBailout: true,
optimizeServerReact: true,
useEarlyImport: false,
staleTimes: {
dynamic: 30,
static: 300,
},
},
}

Expand Down
10 changes: 10 additions & 0 deletions test/e2e/app-dir/app-client-cache/app/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ export default function HomePage() {
To Random Number - prefetch: true
</Link>
</div>
<div>
<Link href="/0?timeout=1000" prefetch={true}>
To Random Number - prefetch: true, slow
</Link>
</div>
<div>
<Link href="/1">To Random Number - prefetch: auto</Link>
</div>
Expand All @@ -15,6 +20,11 @@ export default function HomePage() {
To Random Number 2 - prefetch: false
</Link>
</div>
<div>
<Link href="/2?timeout=1000" prefetch={false}>
To Random Number 2 - prefetch: false, slow
</Link>
</div>
<div>
<Link href="/1?timeout=1000">
To Random Number - prefetch: auto, slow
Expand Down
21 changes: 21 additions & 0 deletions test/e2e/app-dir/app-client-cache/app/without-loading/[id]/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Link from 'next/link'

export default async function Page({ searchParams: { timeout } }) {
const randomNumber = await new Promise((resolve) => {
setTimeout(
() => {
resolve(Math.random())
},
timeout !== undefined ? Number.parseInt(timeout, 10) : 0
)
})

return (
<>
<div>
<Link href="/without-loading">Back to Home</Link>
</div>
<div id="random-number">{randomNumber}</div>
</>
)
}
36 changes: 36 additions & 0 deletions test/e2e/app-dir/app-client-cache/app/without-loading/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Link from 'next/link'

export default function Page() {
return (
<>
<div>
<Link href="/without-loading/0?timeout=0" prefetch={true}>
To Random Number - prefetch: true
</Link>
</div>
<div>
<Link href="/without-loading/0?timeout=1000" prefetch={true}>
To Random Number - prefetch: true, slow
</Link>
</div>
<div>
<Link href="/without-loading/1">To Random Number - prefetch: auto</Link>
</div>
<div>
<Link href="/without-loading/2" prefetch={false}>
To Random Number 2 - prefetch: false
</Link>
</div>
<div>
<Link href="/without-loading/2?timeout=1000" prefetch={false}>
To Random Number 2 - prefetch: false, slow
</Link>
</div>
<div>
<Link href="/without-loading/1?timeout=1000">
To Random Number - prefetch: auto, slow
</Link>
</div>
</>
)
}
Loading