Skip to content

Commit

Permalink
simplify API to only support 'live' | 'default' modes
Browse files Browse the repository at this point in the history
  • Loading branch information
ztanner committed Mar 28, 2024
1 parent 1d8c0f7 commit e9c1b18
Show file tree
Hide file tree
Showing 8 changed files with 435 additions and 626 deletions.
9 changes: 2 additions & 7 deletions packages/next/src/build/webpack/plugins/define-env-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,8 @@ 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_CACHE_STALETIME_MS': JSON.stringify(
config.experimental.clientRouterCache
? 31556952000 // 1 year (ms)
: config.experimental.clientRouterCache === false
? 0
: 30000 // 30 seconds (ms)
),
'process.env.__NEXT_CLIENT_ROUTER_CACHE_MODE':
config.experimental.clientRouterCacheMode ?? 'default',
'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 @@ -8,7 +8,7 @@ import {
type PrefetchCacheEntry,
PrefetchKind,
type ReadonlyReducerState,
PREFETCH_STALE_TIME,
PREFETCH_CACHE_MODE,
} from './router-reducer-types'
import { prefetchQueue } from './reducers/prefetch-reducer'

Expand Down Expand Up @@ -114,8 +114,7 @@ export function getOrCreatePrefetchCacheEntry({
kind:
kind ||
// in dev, there's never gonna be a prefetch entry so we want to prefetch here
// when staletime is 0, there'll never be a "FULL" prefetch kind, so we default to auto
(process.env.NODE_ENV === 'development' || PREFETCH_STALE_TIME === 0
(process.env.NODE_ENV === 'development'
? PrefetchKind.AUTO
: PrefetchKind.TEMPORARY),
})
Expand Down Expand Up @@ -246,21 +245,23 @@ export function prunePrefetchCache(
}

const FIVE_MINUTES = 5 * 60 * 1000
const THIRTY_SECONDS = 30 * 1000

function getPrefetchEntryCacheStatus({
kind,
prefetchTime,
lastUsedTime,
}: PrefetchCacheEntry): PrefetchCacheEntryStatus {
if (PREFETCH_STALE_TIME === 0) {
// a value of 0 means we never want to use the prefetch data, only the prefetched loading state (if it exists)
// we mark it stale here so that the router will not attempt to apply the cache node data and will instead know to lazily
// fetch the full data
if (kind !== PrefetchKind.FULL && PREFETCH_CACHE_MODE === 'live') {
// When the cache mode is set to "live", we only want to re-use the loading state. We mark the entry as stale
// regardless of the lastUsedTime so that the router will not attempt to apply the cache node data and will instead only
// re-use the loading state while lazy fetching the page data.
// We don't do this for a full prefetch, as if there's explicit caching intent it should respect existing heuristics.
return PrefetchCacheEntryStatus.stale
}

// if the cache entry was prefetched or read less than the specified staletime window, then we want to re-use it
if (Date.now() < (lastUsedTime ?? prefetchTime) + PREFETCH_STALE_TIME) {
if (Date.now() < (lastUsedTime ?? prefetchTime) + THIRTY_SECONDS) {
return lastUsedTime
? PrefetchCacheEntryStatus.reusable
: PrefetchCacheEntryStatus.fresh
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,9 @@ export function isThenable(value: any): value is Promise<AppRouterState> {
}

/**
* Time (in ms) that a prefetch entry can be reused by the client router cache.
* A `live` value will indicate that the client router should always fetch the latest data from the server when
* navigating to a new route when auto prefetching is used. A `default` value will use existing
* cache heuristics (router cache will persist for 30s before being invalidated). Defaults to `default`.
*/
export const PREFETCH_STALE_TIME =
typeof process.env.__NEXT_CLIENT_ROUTER_CACHE_STALETIME_MS !== 'undefined'
? parseInt(process.env.__NEXT_CLIENT_ROUTER_CACHE_STALETIME_MS, 10)
: 30 * 1000 // thirty seconds (in ms)
export const PREFETCH_CACHE_MODE =
process.env.__NEXT_CLIENT_ROUTER_CACHE_MODE === 'live' ? 'live' : 'default'
11 changes: 2 additions & 9 deletions packages/next/src/client/link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ import type {
import { useIntersection } from './use-intersection'
import { getDomainLocale } from './get-domain-locale'
import { addBasePath } from './add-base-path'
import {
PREFETCH_STALE_TIME,
PrefetchKind,
} from './components/router-reducer/router-reducer-types'
import { PrefetchKind } from './components/router-reducer/router-reducer-types'

type Url = string | UrlObject
type RequiredKeys<T> = {
Expand Down Expand Up @@ -310,11 +307,7 @@ const Link = React.forwardRef<HTMLAnchorElement, LinkPropsReal>(
* - false: we will not prefetch if in the viewport at all
*/
const appPrefetchKind =
// If the prefetch staletime is 0, then a full prefetch would be wasteful, as it'd never get used.
// These get switched into "auto" so at least the loading state can be re-used.
prefetchProp === null || PREFETCH_STALE_TIME === 0
? PrefetchKind.AUTO
: PrefetchKind.FULL
prefetchProp === null ? PrefetchKind.AUTO : PrefetchKind.FULL

if (process.env.NODE_ENV !== 'production') {
function createPropError(args: {
Expand Down
5 changes: 4 additions & 1 deletion packages/next/src/server/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,10 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
validator: z.string().optional(),
})
.optional(),
clientRouterCache: z.boolean().optional(),
clientRouterCacheMode: z.union([
z.literal('default'),
z.literal('live'),
]),
clientRouterFilter: z.boolean().optional(),
clientRouterFilterRedirects: z.boolean().optional(),
clientRouterFilterAllowedRate: z.number().optional(),
Expand Down
12 changes: 6 additions & 6 deletions packages/next/src/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,12 @@ export interface ExperimentalConfig {
clientRouterFilter?: boolean
clientRouterFilterRedirects?: boolean
/**
* Used to control the router cache "stale time" value. This value is used to determine
* if a cache entry can be re-used, and for how long. `true` means "forever" (implemented as
* one year), `false` means "never" (will always fetch from the server), and undefined will use
* the existing heuristics (30s for dynamic routes, 5min for static routes)
* This value can be used to override the cache behavior for the client router. A `live` value
* will indicate that the client router should always fetch the latest data from the server when
* navigating to a new route when auto prefetching is used. A `default` value will use existing
* cache heuristics (router cache will persist for 30s before being invalidated). Defaults to `default`.
*/
clientRouterCache?: boolean
clientRouterCacheMode?: 'live' | 'default'
// 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 @@ -933,7 +933,7 @@ export const defaultConfig: NextConfig = {
missingSuspenseWithCSRBailout: true,
optimizeServerReact: true,
useEarlyImport: false,
clientRouterCache: undefined,
clientRouterCacheMode: 'default',
},
}

Expand Down
Loading

0 comments on commit e9c1b18

Please sign in to comment.