Skip to content

Commit f2932ea

Browse files
committed
Clean up require.cache handling
Follow-up from #68535. Since the `require.cache` handling is not specific for Webpack, we move the helper functions out of `nextjs-require-cache-hot-reloader.ts`. In addition, when deleting an entry from the `require.cache`, while cleaning up its references in the `children` of parent modules, we now consider all entries in the `require.cache` instead of relying on a list of "origin modules". This list had entries that were not needed, most notably the server runtime bundles (the experimental runtimes were even missing), and at least one (`node-manifest-loader`) was also missing. This has a negligible effect on performance. Handling 1200 `require.cache` entries takes 0.3ms on an M2. The approach was also previously aligned with @sokra.
1 parent aac7382 commit f2932ea

File tree

6 files changed

+49
-79
lines changed

6 files changed

+49
-79
lines changed

packages/next/src/build/webpack/plugins/nextjs-require-cache-hot-reloader.ts

Lines changed: 1 addition & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,12 @@
11
import type { webpack } from 'next/dist/compiled/webpack/webpack'
2+
import { deleteCache } from '../../../server/dev/require-cache'
23
import { clearModuleContext } from '../../../server/web/sandbox'
3-
import { realpathSync } from '../../../lib/realpath'
44
import path from 'path'
5-
import isError from '../../../lib/is-error'
6-
import { clearManifestCache } from '../../../server/load-manifest'
75

86
type Compiler = webpack.Compiler
97
type WebpackPluginInstance = webpack.WebpackPluginInstance
108

11-
const originModules = [
12-
require.resolve('../../../server/require'),
13-
require.resolve('../../../server/load-components'),
14-
require.resolve('../../../server/next-server'),
15-
require.resolve('next/dist/compiled/next-server/app-page.runtime.dev.js'),
16-
require.resolve('next/dist/compiled/next-server/app-route.runtime.dev.js'),
17-
require.resolve('next/dist/compiled/next-server/pages.runtime.dev.js'),
18-
require.resolve('next/dist/compiled/next-server/pages-api.runtime.dev.js'),
19-
]
20-
219
const RUNTIME_NAMES = ['webpack-runtime', 'webpack-api-runtime']
22-
23-
function deleteFromRequireCache(filePath: string) {
24-
try {
25-
filePath = realpathSync(filePath)
26-
} catch (e) {
27-
if (isError(e) && e.code !== 'ENOENT') throw e
28-
}
29-
const mod = require.cache[filePath]
30-
if (mod) {
31-
// remove the child reference from the originModules
32-
for (const originModule of originModules) {
33-
const parent = require.cache[originModule]
34-
if (parent) {
35-
const idx = parent.children.indexOf(mod)
36-
if (idx >= 0) parent.children.splice(idx, 1)
37-
}
38-
}
39-
// remove parent references from external modules
40-
for (const child of mod.children) {
41-
child.parent = null
42-
}
43-
delete require.cache[filePath]
44-
return true
45-
}
46-
return false
47-
}
48-
49-
export function deleteAppClientCache() {
50-
deleteFromRequireCache(
51-
require.resolve('next/dist/compiled/next-server/app-page.runtime.dev.js')
52-
)
53-
deleteFromRequireCache(
54-
require.resolve(
55-
'next/dist/compiled/next-server/app-page-experimental.runtime.dev.js'
56-
)
57-
)
58-
}
59-
60-
export function deleteCache(filePath: string) {
61-
// try to clear it from the fs cache
62-
clearManifestCache(filePath)
63-
64-
deleteFromRequireCache(filePath)
65-
}
66-
6710
const PLUGIN_NAME = 'NextJsRequireCacheHotReloader'
6811

6912
// This plugin flushes require.cache after emitting the files. Providing 'hot reloading' of server files.

packages/next/src/server/dev/hot-reloader-turbopack.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ import { BLOCKED_PAGES } from '../../shared/lib/constants'
3131
import { getOverlayMiddleware } from '../../client/components/react-dev-overlay/server/middleware-turbopack'
3232
import { PageNotFoundError } from '../../shared/lib/utils'
3333
import { debounce } from '../utils'
34-
import {
35-
deleteAppClientCache,
36-
deleteCache,
37-
} from '../../build/webpack/plugins/nextjs-require-cache-hot-reloader'
34+
import { deleteAppClientCache, deleteCache } from './require-cache'
3835
import {
3936
clearAllModuleContexts,
4037
clearModuleContext,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import isError from '../../lib/is-error'
2+
import { realpathSync } from '../../lib/realpath'
3+
import { clearManifestCache } from '../load-manifest'
4+
5+
function deleteFromRequireCache(filePath: string) {
6+
try {
7+
filePath = realpathSync(filePath)
8+
} catch (e) {
9+
if (isError(e) && e.code !== 'ENOENT') throw e
10+
}
11+
const mod = require.cache[filePath]
12+
if (mod) {
13+
// remove the child reference from all parent modules
14+
for (const parent of Object.values(require.cache)) {
15+
if (parent?.children) {
16+
const idx = parent.children.indexOf(mod)
17+
if (idx >= 0) parent.children.splice(idx, 1)
18+
}
19+
}
20+
// remove parent references from external modules
21+
for (const child of mod.children) {
22+
child.parent = null
23+
}
24+
delete require.cache[filePath]
25+
return true
26+
}
27+
return false
28+
}
29+
30+
export function deleteAppClientCache() {
31+
deleteFromRequireCache(
32+
require.resolve('next/dist/compiled/next-server/app-page.runtime.dev.js')
33+
)
34+
deleteFromRequireCache(
35+
require.resolve(
36+
'next/dist/compiled/next-server/app-page-experimental.runtime.dev.js'
37+
)
38+
)
39+
}
40+
41+
export function deleteCache(filePath: string) {
42+
// try to clear it from the fs cache
43+
clearManifestCache(filePath)
44+
45+
deleteFromRequireCache(filePath)
46+
}

packages/next/src/server/dev/turbopack/manifest-loader.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
import { join, posix } from 'path'
2828
import { readFile, writeFile } from 'fs/promises'
2929
import type { SetupOpts } from '../../lib/router-utils/setup-dev-bundler'
30-
import { deleteCache } from '../../../build/webpack/plugins/nextjs-require-cache-hot-reloader'
30+
import { deleteCache } from '../require-cache'
3131
import { writeFileAtomic } from '../../../lib/fs/write-atomic'
3232
import { isInterceptionRouteRewrite } from '../../../lib/generate-interception-routes-rewrites'
3333
import {

packages/next/src/server/lib/render-server.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,9 @@ let initializations: Record<
2020
> = {}
2121

2222
let sandboxContext: undefined | typeof import('../web/sandbox/context')
23-
let requireCacheHotReloader:
24-
| undefined
25-
| typeof import('../../build/webpack/plugins/nextjs-require-cache-hot-reloader')
2623

2724
if (process.env.NODE_ENV !== 'production') {
2825
sandboxContext = require('../web/sandbox/context')
29-
requireCacheHotReloader = require('../../build/webpack/plugins/nextjs-require-cache-hot-reloader')
3026
}
3127

3228
export function clearAllModuleContexts() {
@@ -37,16 +33,6 @@ export function clearModuleContext(target: string) {
3733
return sandboxContext?.clearModuleContext(target)
3834
}
3935

40-
export function deleteAppClientCache() {
41-
return requireCacheHotReloader?.deleteAppClientCache()
42-
}
43-
44-
export function deleteCache(filePaths: string[]) {
45-
for (const filePath of filePaths) {
46-
requireCacheHotReloader?.deleteCache(filePath)
47-
}
48-
}
49-
5036
export async function getServerField(
5137
dir: string,
5238
field: PropagateToWorkersField

packages/next/src/server/lib/router-server.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,7 @@ const isNextFont = (pathname: string | null) =>
5454
export type RenderServer = Pick<
5555
typeof import('./render-server'),
5656
| 'initialize'
57-
| 'deleteCache'
5857
| 'clearModuleContext'
59-
| 'deleteAppClientCache'
6058
| 'propagateServerField'
6159
| 'getServerField'
6260
>

0 commit comments

Comments
 (0)