diff --git a/packages/next/src/server/lib/incremental-cache/file-system-cache.ts b/packages/next/src/server/lib/incremental-cache/file-system-cache.ts index cbfd3fcff5e8..51bd58dabbf4 100644 --- a/packages/next/src/server/lib/incremental-cache/file-system-cache.ts +++ b/packages/next/src/server/lib/incremental-cache/file-system-cache.ts @@ -1,5 +1,5 @@ import type { RouteMetadata } from '../../../export/routes/types' -import type { CacheHandler, CacheHandlerContext, CacheHandlerValue } from './' +import type { CacheHandler, CacheHandlerContext, CacheHandlerValue } from '.' import type { CacheFs } from '../../../shared/lib/utils' import { CachedRouteKind, @@ -10,7 +10,7 @@ import { type SetIncrementalResponseCacheContext, } from '../../response-cache' -import { LRUCache } from '../lru-cache' +import type { LRUCache } from '../lru-cache' import path from '../../../shared/lib/isomorphic/path' import { NEXT_CACHE_TAGS_HEADER, @@ -23,6 +23,7 @@ import { } from '../../../lib/constants' import { isStale, tagsManifest } from './tags-manifest.external' import { MultiFileWriter } from '../../../lib/multi-file-writer' +import { getMemoryCache } from './memory-cache.external' type FileSystemCacheContext = Omit< CacheHandlerContext, @@ -32,54 +33,31 @@ type FileSystemCacheContext = Omit< serverDistDir: string } -let memoryCache: LRUCache | undefined - export default class FileSystemCache implements CacheHandler { private fs: FileSystemCacheContext['fs'] private flushToDisk?: FileSystemCacheContext['flushToDisk'] private serverDistDir: FileSystemCacheContext['serverDistDir'] private revalidatedTags: string[] - private debug: boolean + private static debug: boolean = !!process.env.NEXT_PRIVATE_DEBUG_CACHE + private static memoryCache: LRUCache | undefined constructor(ctx: FileSystemCacheContext) { this.fs = ctx.fs this.flushToDisk = ctx.flushToDisk this.serverDistDir = ctx.serverDistDir this.revalidatedTags = ctx.revalidatedTags - this.debug = !!process.env.NEXT_PRIVATE_DEBUG_CACHE if (ctx.maxMemoryCacheSize) { - if (!memoryCache) { - if (this.debug) { + if (!FileSystemCache.memoryCache) { + if (FileSystemCache.debug) { console.log('using memory store for fetch cache') } - memoryCache = new LRUCache(ctx.maxMemoryCacheSize, function length({ - value, - }) { - if (!value) { - return 25 - } else if (value.kind === CachedRouteKind.REDIRECT) { - return JSON.stringify(value.props).length - } else if (value.kind === CachedRouteKind.IMAGE) { - throw new Error('invariant image should not be incremental-cache') - } else if (value.kind === CachedRouteKind.FETCH) { - return JSON.stringify(value.data || '').length - } else if (value.kind === CachedRouteKind.APP_ROUTE) { - return value.body.length - } - // rough estimate of size of cache value - return ( - value.html.length + - (JSON.stringify( - value.kind === CachedRouteKind.APP_PAGE - ? value.rscData - : value.pageData - )?.length || 0) - ) - }) + FileSystemCache.memoryCache = getMemoryCache(ctx.maxMemoryCacheSize) + } else if (FileSystemCache.debug) { + console.log('memory store already initialized') } - } else if (this.debug) { + } else if (FileSystemCache.debug) { console.log('not using memory store for fetch cache') } } @@ -92,7 +70,7 @@ export default class FileSystemCache implements CacheHandler { let [tags] = args tags = typeof tags === 'string' ? [tags] : tags - if (this.debug) { + if (FileSystemCache.debug) { console.log('revalidateTag', tags) } @@ -111,9 +89,9 @@ export default class FileSystemCache implements CacheHandler { const [key, ctx] = args const { kind } = ctx - let data = memoryCache?.get(key) + let data = FileSystemCache.memoryCache?.get(key) - if (this.debug) { + if (FileSystemCache.debug) { if (kind === IncrementalCacheKind.FETCH) { console.log('get', key, ctx.tags, kind, !!data) } else { @@ -182,7 +160,7 @@ export default class FileSystemCache implements CacheHandler { // TODO: remove this when we can send the tags // via header on GET same as SET if (!tags?.every((tag) => storedTags?.includes(tag))) { - if (this.debug) { + if (FileSystemCache.debug) { console.log('tags vs storedTags mismatch', tags, storedTags) } await this.set(key, data.value, { @@ -291,7 +269,7 @@ export default class FileSystemCache implements CacheHandler { } if (data) { - memoryCache?.set(key, data) + FileSystemCache.memoryCache?.set(key, data) } } catch { return null @@ -345,12 +323,12 @@ export default class FileSystemCache implements CacheHandler { data: IncrementalCacheValue | null, ctx: SetIncrementalFetchCacheContext | SetIncrementalResponseCacheContext ) { - memoryCache?.set(key, { + FileSystemCache.memoryCache?.set(key, { value: data, lastModified: Date.now(), }) - if (this.debug) { + if (FileSystemCache.debug) { console.log('set', key) } diff --git a/packages/next/src/server/lib/incremental-cache/memory-cache.external.ts b/packages/next/src/server/lib/incremental-cache/memory-cache.external.ts new file mode 100644 index 000000000000..33ce99e47ed4 --- /dev/null +++ b/packages/next/src/server/lib/incremental-cache/memory-cache.external.ts @@ -0,0 +1,34 @@ +import type { CacheHandlerValue } from '.' +import { CachedRouteKind } from '../../response-cache/types' +import { LRUCache } from '../lru-cache' + +let memoryCache: LRUCache | undefined + +export function getMemoryCache(maxMemoryCacheSize: number) { + if (!memoryCache) { + memoryCache = new LRUCache(maxMemoryCacheSize, function length({ value }) { + if (!value) { + return 25 + } else if (value.kind === CachedRouteKind.REDIRECT) { + return JSON.stringify(value.props).length + } else if (value.kind === CachedRouteKind.IMAGE) { + throw new Error('invariant image should not be incremental-cache') + } else if (value.kind === CachedRouteKind.FETCH) { + return JSON.stringify(value.data || '').length + } else if (value.kind === CachedRouteKind.APP_ROUTE) { + return value.body.length + } + // rough estimate of size of cache value + return ( + value.html.length + + (JSON.stringify( + value.kind === CachedRouteKind.APP_PAGE + ? value.rscData + : value.pageData + )?.length || 0) + ) + }) + } + + return memoryCache +}