Skip to content

Commit 843c06f

Browse files
fix(core): avoid launching default plugins twice (#29539)
<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior Default plugins are launched twice when loading plugins in a workspace that has local plugins: - Once to resolve the local plugin - Once to be used as an actual plugin ## Expected Behavior Default plugins are launched once and reused ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes # --------- Co-authored-by: FrozenPandaz <[email protected]> (cherry picked from commit 0edd110)
1 parent 206a47e commit 843c06f

24 files changed

+540
-468
lines changed

packages/cypress/src/migrations/update-19-6-0/add-e2e-ci-target-defaults.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
parseTargetString,
88
} from '@nx/devkit';
99
import { addE2eCiTargetDefaults as _addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
10-
import { LoadedNxPlugin } from 'nx/src/project-graph/plugins/internal-api';
10+
import { LoadedNxPlugin } from 'nx/src/project-graph/plugins/loaded-nx-plugin';
1111
import type { ConfigurationResult } from 'nx/src/project-graph/utils/project-configuration-utils';
1212
import {
1313
ProjectConfigurationsError,

packages/nx/src/config/to-project-name.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import { TempFs } from '../internal-testing-utils/temp-fs';
33
import { withEnvironmentVariables } from '../internal-testing-utils/with-environment';
44
import { retrieveProjectConfigurations } from '../project-graph/utils/retrieve-workspace-files';
55
import { readNxJson } from './configuration';
6-
import { loadNxPlugins } from '../project-graph/plugins/internal-api';
6+
import {
7+
cleanupPlugins,
8+
getPlugins,
9+
} from '../project-graph/plugins/get-plugins';
710

811
describe('Workspaces', () => {
912
let fs: TempFs;
@@ -40,16 +43,13 @@ describe('Workspaces', () => {
4043
NX_WORKSPACE_ROOT_PATH: fs.tempDir,
4144
},
4245
async () => {
43-
const [plugins, cleanup] = await loadNxPlugins(
44-
readNxJson(fs.tempDir).plugins,
45-
fs.tempDir
46-
);
46+
const plugins = await getPlugins(fs.tempDir);
4747
const res = await retrieveProjectConfigurations(
4848
plugins,
4949
fs.tempDir,
5050
readNxJson(fs.tempDir)
5151
);
52-
cleanup();
52+
cleanupPlugins();
5353
return res;
5454
}
5555
);

packages/nx/src/daemon/server/project-graph-incremental-recomputation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { notifyFileWatcherSockets } from './file-watching/file-watcher-sockets';
3030
import { serverLogger } from './logger';
3131
import { NxWorkspaceFilesExternals } from '../../native';
3232
import { ConfigurationResult } from '../../project-graph/utils/project-configuration-utils';
33-
import { LoadedNxPlugin } from '../../project-graph/plugins/internal-api';
33+
import type { LoadedNxPlugin } from '../../project-graph/plugins/loaded-nx-plugin';
3434
import {
3535
DaemonProjectGraphError,
3636
ProjectConfigurationsError,

packages/nx/src/devkit-internals.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export {
2626
findProjectForPath,
2727
} from './project-graph/utils/find-project-for-path';
2828
export { retrieveProjectConfigurations } from './project-graph/utils/retrieve-workspace-files';
29-
export { LoadedNxPlugin } from './project-graph/plugins/internal-api';
29+
export { LoadedNxPlugin } from './project-graph/plugins/loaded-nx-plugin';
3030
export * from './project-graph/error-types';
3131
export { registerTsProject } from './plugins/js/utils/register';
3232
export { interpolate } from './tasks-runner/utils';

packages/nx/src/plugins/js/project-graph/build-dependencies/explicit-project-dependencies.spec.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const tempFs = new TempFs('explicit-project-deps');
55
import { ProjectGraphProjectNode } from '../../../../config/project-graph';
66
import { ProjectConfiguration } from '../../../../config/workspace-json-project-json';
77
import { CreateDependenciesContext } from '../../../../project-graph/plugins';
8-
import { loadNxPlugins } from '../../../../project-graph/plugins/internal-api';
98
import { ProjectGraphBuilder } from '../../../../project-graph/project-graph-builder';
109
import {
1110
retrieveProjectConfigurations,
@@ -14,6 +13,10 @@ import {
1413
import { setupWorkspaceContext } from '../../../../utils/workspace-context';
1514
import { buildExplicitTypeScriptDependencies } from './explicit-project-dependencies';
1615
import { TargetProjectLocator } from './target-project-locator';
16+
import {
17+
cleanupPlugins,
18+
getOnlyDefaultPlugins,
19+
} from '../../../../project-graph/plugins/get-plugins';
1720

1821
// projectName => tsconfig import path
1922
const dependencyProjectNamesToImportPaths = {
@@ -698,13 +701,13 @@ async function createContext(
698701

699702
setupWorkspaceContext(tempFs.tempDir);
700703

701-
const [plugins, cleanup] = await loadNxPlugins([], tempFs.tempDir);
704+
const plugins = await getOnlyDefaultPlugins(tempFs.tempDir);
702705
const { projects, projectRootMap } = await retrieveProjectConfigurations(
703706
plugins,
704707
tempFs.tempDir,
705708
nxJson
706709
);
707-
cleanup();
710+
cleanupPlugins();
708711

709712
const { fileMap } = await retrieveWorkspaceFiles(
710713
tempFs.tempDir,

packages/nx/src/project-graph/build-project-graph.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from './nx-deps-cache';
1313
import { applyImplicitDependencies } from './utils/implicit-project-dependencies';
1414
import { normalizeProjectNodes } from './utils/normalize-project-nodes';
15-
import { LoadedNxPlugin } from './plugins/internal-api';
15+
import type { LoadedNxPlugin } from './plugins/loaded-nx-plugin';
1616
import {
1717
CreateDependenciesContext,
1818
CreateMetadataContext,

packages/nx/src/project-graph/plugins/get-plugins.ts

Lines changed: 168 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,33 @@
1+
import { join } from 'node:path';
2+
3+
import { shouldMergeAngularProjects } from '../../adapter/angular-json';
4+
import { PluginConfiguration, readNxJson } from '../../config/nx-json';
15
import { hashObject } from '../../hasher/file-hasher';
2-
import { readNxJson } from '../../config/nx-json';
3-
import { LoadedNxPlugin, loadNxPlugins } from './internal-api';
6+
import { IS_WASM } from '../../native';
47
import { workspaceRoot } from '../../utils/workspace-root';
8+
import { loadNxPluginInIsolation } from './isolation';
9+
import { loadNxPlugin } from './in-process-loader';
10+
11+
import type { LoadedNxPlugin } from './loaded-nx-plugin';
12+
import {
13+
cleanupPluginTSTranspiler,
14+
pluginTranspilerIsRegistered,
15+
} from './transpiler';
516

17+
/**
18+
* Stuff for specified NX Plugins.
19+
*/
620
let currentPluginsConfigurationHash: string;
721
let loadedPlugins: LoadedNxPlugin[];
822
let pendingPluginsPromise:
923
| Promise<readonly [LoadedNxPlugin[], () => void]>
1024
| undefined;
11-
let cleanup: () => void;
25+
let cleanup: () => void | undefined;
1226

13-
export async function getPlugins() {
14-
const pluginsConfiguration = readNxJson().plugins ?? [];
27+
export async function getPlugins(
28+
root = workspaceRoot
29+
): Promise<LoadedNxPlugin[]> {
30+
const pluginsConfiguration = readNxJson(root).plugins ?? [];
1531
const pluginsConfigurationHash = hashObject(pluginsConfiguration);
1632

1733
// If the plugins configuration has not changed, reuse the current plugins
@@ -28,22 +44,29 @@ export async function getPlugins() {
2844
cleanup();
2945
}
3046

31-
pendingPluginsPromise ??= loadNxPlugins(pluginsConfiguration, workspaceRoot);
47+
pendingPluginsPromise ??= loadSpecifiedNxPlugins(pluginsConfiguration, root);
3248

3349
currentPluginsConfigurationHash = pluginsConfigurationHash;
34-
const [result, cleanupFn] = await pendingPluginsPromise;
50+
const [[result, cleanupFn], defaultPlugins] = await Promise.all([
51+
pendingPluginsPromise,
52+
getOnlyDefaultPlugins(root),
53+
]);
3554
cleanup = cleanupFn;
36-
loadedPlugins = result;
37-
return result;
55+
loadedPlugins = result.concat(defaultPlugins);
56+
return loadedPlugins;
3857
}
3958

59+
/**
60+
* Stuff for default NX Plugins.
61+
*/
62+
4063
let loadedDefaultPlugins: LoadedNxPlugin[];
4164
let cleanupDefaultPlugins: () => void;
4265
let pendingDefaultPluginPromise:
4366
| Promise<readonly [LoadedNxPlugin[], () => void]>
4467
| undefined;
4568

46-
export async function getOnlyDefaultPlugins() {
69+
export async function getOnlyDefaultPlugins(root = workspaceRoot) {
4770
// If the plugins configuration has not changed, reuse the current plugins
4871
if (loadedDefaultPlugins) {
4972
return loadedPlugins;
@@ -55,7 +78,7 @@ export async function getOnlyDefaultPlugins() {
5578
cleanupDefaultPlugins();
5679
}
5780

58-
pendingDefaultPluginPromise ??= loadNxPlugins([], workspaceRoot);
81+
pendingDefaultPluginPromise ??= loadDefaultNxPlugins(workspaceRoot);
5982

6083
const [result, cleanupFn] = await pendingDefaultPluginPromise;
6184
cleanupDefaultPlugins = cleanupFn;
@@ -66,6 +89,138 @@ export async function getOnlyDefaultPlugins() {
6689
export function cleanupPlugins() {
6790
pendingPluginsPromise = undefined;
6891
pendingDefaultPluginPromise = undefined;
69-
cleanup();
70-
cleanupDefaultPlugins();
92+
cleanup?.();
93+
cleanupDefaultPlugins?.();
94+
}
95+
96+
/**
97+
* Stuff for generic loading
98+
*/
99+
100+
function isIsolationEnabled() {
101+
// Explicitly enabled, regardless of further conditions
102+
if (process.env.NX_ISOLATE_PLUGINS === 'true') {
103+
return true;
104+
}
105+
if (
106+
// Explicitly disabled
107+
process.env.NX_ISOLATE_PLUGINS === 'false' ||
108+
// Isolation is disabled on WASM builds currently.
109+
IS_WASM
110+
) {
111+
return false;
112+
}
113+
// Default value
114+
return true;
115+
}
116+
117+
const loadingMethod = isIsolationEnabled()
118+
? loadNxPluginInIsolation
119+
: loadNxPlugin;
120+
121+
async function loadDefaultNxPlugins(root = workspaceRoot) {
122+
performance.mark('loadDefaultNxPlugins:start');
123+
124+
const plugins = getDefaultPlugins(root);
125+
126+
const cleanupFunctions: Array<() => void> = [];
127+
const ret = [
128+
await Promise.all(
129+
plugins.map(async (plugin) => {
130+
performance.mark(`Load Nx Plugin: ${plugin} - start`);
131+
132+
const [loadedPluginPromise, cleanup] = await loadingMethod(
133+
plugin,
134+
root
135+
);
136+
137+
cleanupFunctions.push(cleanup);
138+
const res = await loadedPluginPromise;
139+
performance.mark(`Load Nx Plugin: ${plugin} - end`);
140+
performance.measure(
141+
`Load Nx Plugin: ${plugin}`,
142+
`Load Nx Plugin: ${plugin} - start`,
143+
`Load Nx Plugin: ${plugin} - end`
144+
);
145+
146+
return res;
147+
})
148+
),
149+
() => {
150+
for (const fn of cleanupFunctions) {
151+
fn();
152+
}
153+
if (pluginTranspilerIsRegistered()) {
154+
cleanupPluginTSTranspiler();
155+
}
156+
},
157+
] as const;
158+
performance.mark('loadDefaultNxPlugins:end');
159+
performance.measure(
160+
'loadDefaultNxPlugins',
161+
'loadDefaultNxPlugins:start',
162+
'loadDefaultNxPlugins:end'
163+
);
164+
return ret;
165+
}
166+
167+
async function loadSpecifiedNxPlugins(
168+
plugins: PluginConfiguration[],
169+
root = workspaceRoot
170+
): Promise<readonly [LoadedNxPlugin[], () => void]> {
171+
performance.mark('loadSpecifiedNxPlugins:start');
172+
173+
plugins ??= [];
174+
175+
const cleanupFunctions: Array<() => void> = [];
176+
const ret = [
177+
await Promise.all(
178+
plugins.map(async (plugin) => {
179+
const pluginPath = typeof plugin === 'string' ? plugin : plugin.plugin;
180+
performance.mark(`Load Nx Plugin: ${pluginPath} - start`);
181+
182+
const [loadedPluginPromise, cleanup] = await loadingMethod(
183+
plugin,
184+
root
185+
);
186+
187+
cleanupFunctions.push(cleanup);
188+
const res = await loadedPluginPromise;
189+
performance.mark(`Load Nx Plugin: ${pluginPath} - end`);
190+
performance.measure(
191+
`Load Nx Plugin: ${pluginPath}`,
192+
`Load Nx Plugin: ${pluginPath} - start`,
193+
`Load Nx Plugin: ${pluginPath} - end`
194+
);
195+
196+
return res;
197+
})
198+
),
199+
() => {
200+
for (const fn of cleanupFunctions) {
201+
fn();
202+
}
203+
if (pluginTranspilerIsRegistered()) {
204+
cleanupPluginTSTranspiler();
205+
}
206+
},
207+
] as const;
208+
performance.mark('loadSpecifiedNxPlugins:end');
209+
performance.measure(
210+
'loadSpecifiedNxPlugins',
211+
'loadSpecifiedNxPlugins:start',
212+
'loadSpecifiedNxPlugins:end'
213+
);
214+
return ret;
215+
}
216+
217+
function getDefaultPlugins(root: string) {
218+
return [
219+
join(__dirname, '../../plugins/js'),
220+
...(shouldMergeAngularProjects(root, false)
221+
? [join(__dirname, '../../adapter/angular-json')]
222+
: []),
223+
join(__dirname, '../../plugins/package-json'),
224+
join(__dirname, '../../plugins/project-json/build-nodes/project-json'),
225+
];
71226
}

0 commit comments

Comments
 (0)