Skip to content

Commit a2881bf

Browse files
piehmrstork
andauthored
perf: memoize blobs requests in the request scope (#2777)
* test: add test case with multiple fetches for same resource and test asserting we only check blobs once per request for same key * refactor: create simplified key-value store interface to interact with blobs with common tracing pattern * refactor: create reusable helper to record warnings * perf: memoize blobs requests in the request scope * refactor: rename RequestSpecificInMemoryCache to RequestScopedInMemoryCache * refactor: modulurize blobs storage abstractions * chore: fix lint * refactor: move non-CacheHandler related types and utils from cache-types to blob-types module * fix: add missing implementation for isTagManifest and isHtmlBlob type guards * chore: drop use of noOpInMemoryCache --------- Co-authored-by: Mateusz Bocian <[email protected]>
1 parent 67d6c7b commit a2881bf

20 files changed

+729
-170
lines changed

.eslintrc.cjs

+8
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ module.exports = {
7272
message: 'Please use `getTracer()` from `./handlers/tracer.cjs` instead',
7373
},
7474
],
75+
patterns: [
76+
{
77+
// only */storage/storage.cjs is allowed to be imported
78+
// rest are implementation details that should not be used directly
79+
group: ['*/storage/*', '!*/storage/storage.cjs'],
80+
message: 'Import public `[...]/storage/storage.cjs` module instead.',
81+
},
82+
],
7583
},
7684
],
7785
},

package-lock.json

+30-46
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"fs-monkey": "^1.0.6",
7777
"get-port": "^7.1.0",
7878
"lambda-local": "^2.2.0",
79+
"lru-cache": "^10.4.3",
7980
"memfs": "^4.9.2",
8081
"mock-require": "^3.0.3",
8182
"msw": "^2.0.7",

src/build/content/static.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { trace } from '@opentelemetry/api'
66
import { wrapTracer } from '@opentelemetry/api/experimental'
77
import glob from 'fast-glob'
88

9-
import type { HtmlBlob } from '../../run/next.cjs'
9+
import type { HtmlBlob } from '../../shared/blob-types.cjs'
1010
import { encodeBlobKey } from '../../shared/blobkey.js'
1111
import { PluginContext } from '../plugin-context.js'
1212
import { verifyNetlifyForms } from '../verification.js'

src/run/config.ts

+26-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { join, resolve } from 'node:path'
55
import type { NextConfigComplete } from 'next/dist/server/config-shared.js'
66

77
import { PLUGIN_DIR, RUN_CONFIG } from './constants.js'
8+
import { setInMemoryCacheMaxSizeFromNextConfig } from './storage/storage.cjs'
89

910
/**
1011
* Get Next.js config from the build output
@@ -13,10 +14,27 @@ export const getRunConfig = async () => {
1314
return JSON.parse(await readFile(resolve(PLUGIN_DIR, RUN_CONFIG), 'utf-8'))
1415
}
1516

17+
type NextConfigForMultipleVersions = NextConfigComplete & {
18+
experimental: NextConfigComplete['experimental'] & {
19+
// those are pre 14.1.0 options that were moved out of experimental in // https://github.com/vercel/next.js/pull/57953/files#diff-c49c4767e6ed8627e6e1b8f96b141ee13246153f5e9142e1da03450c8e81e96fL311
20+
21+
// https://github.com/vercel/next.js/blob/v14.0.4/packages/next/src/server/config-shared.ts#L182-L183
22+
// custom path to a cache handler to use
23+
incrementalCacheHandlerPath?: string
24+
// https://github.com/vercel/next.js/blob/v14.0.4/packages/next/src/server/config-shared.ts#L207-L212
25+
/**
26+
* In-memory cache size in bytes.
27+
*
28+
* If `isrMemoryCacheSize: 0` disables in-memory caching.
29+
*/
30+
isrMemoryCacheSize?: number
31+
}
32+
}
33+
1634
/**
1735
* Configure the custom cache handler at request time
1836
*/
19-
export const setRunConfig = (config: NextConfigComplete) => {
37+
export const setRunConfig = (config: NextConfigForMultipleVersions) => {
2038
const cacheHandler = join(PLUGIN_DIR, '.netlify/dist/run/handlers/cache.cjs')
2139
if (!existsSync(cacheHandler)) {
2240
throw new Error(`Cache handler not found at ${cacheHandler}`)
@@ -25,15 +43,17 @@ export const setRunConfig = (config: NextConfigComplete) => {
2543
// set the path to the cache handler
2644
config.experimental = {
2745
...config.experimental,
28-
// @ts-expect-error incrementalCacheHandlerPath was removed from config type
29-
// but we still need to set it for older Next.js versions
46+
// Before Next.js 14.1.0 path to the cache handler was in experimental section, see NextConfigForMultipleVersions type
3047
incrementalCacheHandlerPath: cacheHandler,
3148
}
3249

33-
// Next.js 14.1.0 moved the cache handler from experimental to stable
34-
// https://github.com/vercel/next.js/pull/57953/files#diff-c49c4767e6ed8627e6e1b8f96b141ee13246153f5e9142e1da03450c8e81e96fL311
50+
// Next.js 14.1.0 moved the cache handler from experimental to stable, see NextConfigForMultipleVersions type
3551
config.cacheHandler = cacheHandler
36-
config.cacheMaxMemorySize = 0
52+
53+
// honor the in-memory cache size from next.config (either one set by user or Next.js default)
54+
setInMemoryCacheMaxSizeFromNextConfig(
55+
config.cacheMaxMemorySize ?? config.experimental?.isrMemoryCacheSize,
56+
)
3757

3858
// set config
3959
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(config)

0 commit comments

Comments
 (0)