Skip to content

Commit f4ea297

Browse files
AgentEnderFrozenPandaz
authored andcommitted
fix(misc): don't clear node_modules require cache (#22907)
(cherry picked from commit 80b5514)
1 parent 39f8713 commit f4ea297

File tree

6 files changed

+32
-101
lines changed

6 files changed

+32
-101
lines changed

packages/devkit/src/utils/config-utils.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { dirname, extname, join } from 'path';
1+
import { dirname, extname, join, sep } from 'path';
22
import { existsSync, readdirSync } from 'fs';
33
import { requireNx } from '../../nx';
44
import { pathToFileURL } from 'node:url';
@@ -54,15 +54,26 @@ export function getRootTsConfigFileName(): string | null {
5454
return null;
5555
}
5656

57+
const packageInstallationDirectories = [
58+
`${sep}node_modules${sep}`,
59+
`${sep}.yarn${sep}`,
60+
];
61+
62+
export function clearRequireCache(): void {
63+
for (const k of Object.keys(require.cache)) {
64+
if (!packageInstallationDirectories.some((dir) => k.includes(dir))) {
65+
delete require.cache[k];
66+
}
67+
}
68+
}
69+
5770
/**
5871
* Load the module after ensuring that the require cache is cleared.
5972
*/
6073
async function load(path: string): Promise<any> {
6174
// Clear cache if the path is in the cache
6275
if (require.cache[path]) {
63-
for (const k of Object.keys(require.cache)) {
64-
delete require.cache[k];
65-
}
76+
clearRequireCache();
6677
}
6778

6879
try {

packages/expo/plugins/plugin.ts

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
1515
import { existsSync, readdirSync } from 'fs';
1616
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
1717
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
18+
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
1819

1920
export interface ExpoPluginOptions {
2021
startTargetName?: string;
@@ -59,7 +60,7 @@ export const createDependencies: CreateDependencies = () => {
5960

6061
export const createNodes: CreateNodes<ExpoPluginOptions> = [
6162
'**/app.{json,config.js}',
62-
(configFilePath, options, context) => {
63+
async (configFilePath, options, context) => {
6364
options = normalizeOptions(options);
6465
const projectRoot = dirname(configFilePath);
6566

@@ -71,7 +72,7 @@ export const createNodes: CreateNodes<ExpoPluginOptions> = [
7172
) {
7273
return {};
7374
}
74-
const appConfig = getAppConfig(configFilePath, context);
75+
const appConfig = await getAppConfig(configFilePath, context);
7576
// if appConfig.expo is not defined
7677
if (!appConfig.expo) {
7778
return {};
@@ -152,11 +153,10 @@ function buildExpoTargets(
152153
function getAppConfig(
153154
configFilePath: string,
154155
context: CreateNodesContext
155-
): any {
156+
): Promise<any> {
156157
const resolvedPath = join(context.workspaceRoot, configFilePath);
157158

158-
let module = load(resolvedPath);
159-
return module.default ?? module;
159+
return loadConfigFile(resolvedPath);
160160
}
161161

162162
function getInputs(
@@ -180,21 +180,6 @@ function getOutputs(projectRoot: string, dir: string) {
180180
}
181181
}
182182

183-
/**
184-
* Load the module after ensuring that the require cache is cleared.
185-
*/
186-
function load(path: string): any {
187-
// Clear cache if the path is in the cache
188-
if (require.cache[path]) {
189-
for (const k of Object.keys(require.cache)) {
190-
delete require.cache[k];
191-
}
192-
}
193-
194-
// Then require
195-
return require(path);
196-
}
197-
198183
function normalizeOptions(options: ExpoPluginOptions): ExpoPluginOptions {
199184
options ??= {};
200185
options.startTargetName ??= 'start';

packages/jest/src/plugins/plugin.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { existsSync, readdirSync, readFileSync } from 'fs';
1616
import { readConfig } from 'jest-config';
1717
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
1818
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
19+
import { clearRequireCache } from '@nx/devkit/src/utils/config-utils';
1920
import { getGlobPatternsFromPackageManagerWorkspaces } from 'nx/src/plugins/package-json-workspaces';
2021
import { combineGlobPatterns } from 'nx/src/utils/globs';
2122
import { minimatch } from 'minimatch';
@@ -109,12 +110,6 @@ export const createNodes: CreateNodes<JestPluginOptions> = [
109110
},
110111
];
111112

112-
const jestValidatePath = dirname(
113-
require.resolve('jest-validate/package.json', {
114-
paths: [dirname(require.resolve('jest-config'))],
115-
})
116-
);
117-
118113
async function buildJestTargets(
119114
configFilePath: string,
120115
projectRoot: string,
@@ -124,13 +119,7 @@ async function buildJestTargets(
124119
const absConfigFilePath = resolve(context.workspaceRoot, configFilePath);
125120

126121
if (require.cache[absConfigFilePath]) {
127-
for (const k of Object.keys(require.cache)) {
128-
// Only delete the cache outside of jest-validate
129-
// jest-validate has a Symbol which is important for jest config validation which breaks if the require cache is broken
130-
if (relative(jestValidatePath, k).startsWith('../')) {
131-
delete require.cache[k];
132-
}
133-
}
122+
clearRequireCache();
134123
}
135124

136125
const config = await readConfig(

packages/next/src/plugins/plugin.ts

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { existsSync, readdirSync } from 'fs';
1616
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
1717
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
1818
import { getLockFileName } from '@nx/js';
19+
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
1920

2021
export interface NextPluginOptions {
2122
buildTargetName?: string;
@@ -194,19 +195,13 @@ async function getOutputs(projectRoot, nextConfig) {
194195
}
195196
}
196197

197-
async function getNextConfig(
198+
function getNextConfig(
198199
configFilePath: string,
199200
context: CreateNodesContext
200201
): Promise<any> {
201202
const resolvedPath = join(context.workspaceRoot, configFilePath);
202203

203-
let module;
204-
if (extname(configFilePath) === '.mjs') {
205-
module = await loadEsmModule(resolvedPath);
206-
} else {
207-
module = load(resolvedPath);
208-
}
209-
return module.default ?? module;
204+
return loadConfigFile(resolvedPath);
210205
}
211206

212207
function normalizeOptions(options: NextPluginOptions): NextPluginOptions {
@@ -230,36 +225,3 @@ function getInputs(
230225
},
231226
];
232227
}
233-
234-
const packageInstallationDirectories = ['node_modules', '.yarn'];
235-
/**
236-
* Load the module after ensuring that the require cache is cleared.
237-
*/
238-
function load(path: string): any {
239-
// Clear cache if the path is in the cache
240-
if (require.cache[path]) {
241-
for (const key of Object.keys(require.cache)) {
242-
if (!packageInstallationDirectories.some((dir) => key.includes(dir))) {
243-
delete require.cache[key];
244-
}
245-
}
246-
}
247-
248-
// Then require
249-
return require(path);
250-
}
251-
252-
/**
253-
* Lazily compiled dynamic import loader function.
254-
*/
255-
let dynamicLoad: (<T>(modulePath: string | URL) => Promise<T>) | undefined;
256-
257-
export function loadEsmModule<T>(modulePath: string | URL): Promise<T> {
258-
const modulePathWithCacheBust = `${modulePath}?version=${Date.now()}`;
259-
dynamicLoad ??= new Function(
260-
'modulePath',
261-
`return import(modulePath);`
262-
) as Exclude<typeof dynamicLoad, undefined>;
263-
264-
return dynamicLoad(modulePathWithCacheBust);
265-
}

packages/react-native/plugins/plugin.ts

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
1515
import { existsSync, readdirSync } from 'fs';
1616
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
1717
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
18+
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
1819

1920
export interface ReactNativePluginOptions {
2021
startTargetName?: string;
@@ -59,7 +60,7 @@ export const createDependencies: CreateDependencies = () => {
5960

6061
export const createNodes: CreateNodes<ReactNativePluginOptions> = [
6162
'**/app.{json,config.js}',
62-
(configFilePath, options, context) => {
63+
async (configFilePath, options, context) => {
6364
options = normalizeOptions(options);
6465
const projectRoot = dirname(configFilePath);
6566

@@ -71,7 +72,7 @@ export const createNodes: CreateNodes<ReactNativePluginOptions> = [
7172
) {
7273
return {};
7374
}
74-
const appConfig = getAppConfig(configFilePath, context);
75+
const appConfig = await getAppConfig(configFilePath, context);
7576
if (appConfig.expo) {
7677
return {};
7778
}
@@ -164,11 +165,10 @@ function buildReactNativeTargets(
164165
function getAppConfig(
165166
configFilePath: string,
166167
context: CreateNodesContext
167-
): any {
168+
): Promise<any> {
168169
const resolvedPath = join(context.workspaceRoot, configFilePath);
169170

170-
let module = load(resolvedPath);
171-
return module.default ?? module;
171+
return loadConfigFile(resolvedPath);
172172
}
173173

174174
function getInputs(
@@ -192,21 +192,6 @@ function getOutputs(projectRoot: string, dir: string) {
192192
}
193193
}
194194

195-
/**
196-
* Load the module after ensuring that the require cache is cleared.
197-
*/
198-
function load(path: string): any {
199-
// Clear cache if the path is in the cache
200-
if (require.cache[path]) {
201-
for (const k of Object.keys(require.cache)) {
202-
delete require.cache[k];
203-
}
204-
}
205-
206-
// Then require
207-
return require(path);
208-
}
209-
210195
function normalizeOptions(
211196
options: ReactNativePluginOptions
212197
): ReactNativePluginOptions {

packages/webpack/src/utils/webpack/resolve-user-defined-webpack-config.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { registerTsProject } from '@nx/js/src/internal';
2+
import { clearRequireCache } from '@nx/devkit/src/utils/config-utils';
23

34
export function resolveUserDefinedWebpackConfig(
45
path: string,
@@ -10,9 +11,7 @@ export function resolveUserDefinedWebpackConfig(
1011
// Clear cache if the path is in the cache
1112
if (require.cache[path]) {
1213
// Clear all entries because config may import other modules
13-
for (const k of Object.keys(require.cache)) {
14-
delete require.cache[k];
15-
}
14+
clearRequireCache();
1615
}
1716
}
1817

0 commit comments

Comments
 (0)