nx 23.3.0-beta.1 → 23.3.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +0 -3
- package/dist/src/command-line/init/implementation/add-nx-to-nest.js +0 -3
- package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +0 -3
- package/dist/src/command-line/init/implementation/angular/index.js +0 -3
- package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +0 -3
- package/dist/src/command-line/init/implementation/utils.d.ts +0 -1
- package/dist/src/command-line/init/implementation/utils.js +0 -8
- package/dist/src/command-line/init/init-v2.js +0 -3
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +0 -10
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/daemon/client/client.d.ts +2 -0
- package/dist/src/daemon/client/client.js +7 -0
- package/dist/src/daemon/message-types/get-plugin-capabilities.d.ts +5 -0
- package/dist/src/daemon/message-types/get-plugin-capabilities.js +11 -0
- package/dist/src/daemon/server/handle-get-plugin-capabilities.d.ts +2 -0
- package/dist/src/daemon/server/handle-get-plugin-capabilities.js +13 -0
- package/dist/src/daemon/server/project-graph-incremental-recomputation.js +1 -1
- package/dist/src/daemon/server/server.js +5 -0
- package/dist/src/native/index.d.ts +20 -0
- package/dist/src/native/native-bindings.js +1 -0
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/project-graph/affected/locators/project-glob-changes.js +19 -26
- package/dist/src/project-graph/error-types.d.ts +5 -0
- package/dist/src/project-graph/error-types.js +44 -5
- package/dist/src/project-graph/file-utils.d.ts +2 -0
- package/dist/src/project-graph/file-utils.js +6 -1
- package/dist/src/project-graph/nx-deps-cache.d.ts +5 -2
- package/dist/src/project-graph/nx-deps-cache.js +4 -4
- package/dist/src/project-graph/plugins/get-plugins.d.ts +3 -1
- package/dist/src/project-graph/plugins/get-plugins.js +60 -82
- package/dist/src/project-graph/plugins/in-process-loader.d.ts +1 -1
- package/dist/src/project-graph/plugins/in-process-loader.js +1 -4
- package/dist/src/project-graph/plugins/isolation/index.d.ts +1 -1
- package/dist/src/project-graph/plugins/isolation/index.js +3 -1
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +8 -0
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +40 -5
- package/dist/src/project-graph/plugins/isolation/load-isolated-plugin.d.ts +10 -1
- package/dist/src/project-graph/plugins/isolation/load-isolated-plugin.js +67 -17
- package/dist/src/project-graph/plugins/loaded-nx-plugin.d.ts +2 -0
- package/dist/src/project-graph/plugins/loaded-nx-plugin.js +9 -0
- package/dist/src/project-graph/plugins/nx-plugin-capabilities.d.ts +6 -0
- package/dist/src/project-graph/plugins/nx-plugin-capabilities.js +28 -0
- package/dist/src/project-graph/plugins/tasks-execution-hooks.js +12 -0
- package/dist/src/project-graph/project-graph.js +41 -42
- package/dist/src/utils/ab-testing.d.ts +1 -1
- package/dist/src/utils/ab-testing.js +0 -4
- package/dist/src/utils/handle-errors.js +5 -43
- package/dist/src/utils/plugins/plugin-capabilities.js +7 -2
- package/dist/src/utils/serialize-overrides-into-command-line.js +2 -4
- package/package.json +11 -12
|
@@ -7,6 +7,7 @@ exports.getPluginsSeparated = getPluginsSeparated;
|
|
|
7
7
|
exports.getOnlyDefaultPlugins = getOnlyDefaultPlugins;
|
|
8
8
|
exports.getPluginsIfLoadedOrLoading = getPluginsIfLoadedOrLoading;
|
|
9
9
|
exports.cleanupPlugins = cleanupPlugins;
|
|
10
|
+
exports.capabilitiesOfConfiguredPlugins = capabilitiesOfConfiguredPlugins;
|
|
10
11
|
exports.reasonToError = reasonToError;
|
|
11
12
|
const node_path_1 = require("node:path");
|
|
12
13
|
const angular_json_1 = require("../../adapter/angular-json");
|
|
@@ -15,6 +16,9 @@ const workspace_root_1 = require("../../utils/workspace-root");
|
|
|
15
16
|
const in_process_loader_1 = require("./in-process-loader");
|
|
16
17
|
const isolation_1 = require("./isolation");
|
|
17
18
|
const resolve_plugin_1 = require("./resolve-plugin");
|
|
19
|
+
const is_on_daemon_1 = require("../../daemon/is-on-daemon");
|
|
20
|
+
const client_1 = require("../../daemon/client/client");
|
|
21
|
+
const nx_plugin_capabilities_1 = require("./nx-plugin-capabilities");
|
|
18
22
|
const enabled_1 = require("./isolation/enabled");
|
|
19
23
|
const isolated_plugin_1 = require("./isolation/isolated-plugin");
|
|
20
24
|
const sandbox_socket_hint_1 = require("../../daemon/sandbox-socket-hint");
|
|
@@ -26,10 +30,15 @@ const transpiler_1 = require("./transpiler");
|
|
|
26
30
|
* Stuff for specified NX Plugins.
|
|
27
31
|
*/
|
|
28
32
|
let currentPluginsConfigurationHash;
|
|
29
|
-
let loadedPlugins;
|
|
30
33
|
let cachedSeparatedPlugins;
|
|
31
34
|
let pendingPluginsPromise;
|
|
32
|
-
|
|
35
|
+
/** Workers aren't disposed here; the next load's `wantPlugins` sweeps the ones it no longer names. */
|
|
36
|
+
function forgetSpecifiedPlugins() {
|
|
37
|
+
if ((0, transpiler_1.pluginTranspilerIsRegistered)()) {
|
|
38
|
+
(0, transpiler_1.cleanupPluginTSTranspiler)();
|
|
39
|
+
}
|
|
40
|
+
pendingPluginsPromise = undefined;
|
|
41
|
+
}
|
|
33
42
|
// In-flight separated-plugins load, tagged with its hash. Two roles: a
|
|
34
43
|
// concurrent caller for the same set shares this load instead of racing a
|
|
35
44
|
// second one, and it gates the cache commit — a load writes the cache only if
|
|
@@ -74,11 +83,10 @@ const loadingMethod = async (plugin, root, index) => {
|
|
|
74
83
|
if (!(0, enabled_1.isIsolationEnabled)() || isolationRefusedInThisProcess) {
|
|
75
84
|
return (0, in_process_loader_1.loadNxPlugin)(plugin, root, index);
|
|
76
85
|
}
|
|
77
|
-
const [isolatedPlugin, cleanup] = await (0, isolation_1.loadIsolatedNxPlugin)(plugin, root, index);
|
|
78
86
|
// Awaited here rather than handed on, because the worker failure surfaces on
|
|
79
87
|
// this promise and the fallback has to happen before the caller sees it.
|
|
80
88
|
try {
|
|
81
|
-
return
|
|
89
|
+
return await (0, isolation_1.loadIsolatedNxPlugin)(plugin, root, index);
|
|
82
90
|
}
|
|
83
91
|
catch (e) {
|
|
84
92
|
// Proof, kept separate from policy. The errno the worker saw is what makes
|
|
@@ -92,7 +100,6 @@ const loadingMethod = async (plugin, root, index) => {
|
|
|
92
100
|
!((provenRefusal && (0, native_1.isAiAgent)()) || (0, is_sandbox_1.isSandbox)())) {
|
|
93
101
|
throw e;
|
|
94
102
|
}
|
|
95
|
-
cleanup();
|
|
96
103
|
// Read and set in one synchronous step. Concurrently loaded plugins each
|
|
97
104
|
// arrive here with their own failure, so testing the latch after setting it
|
|
98
105
|
// is what keeps the advice to one copy.
|
|
@@ -152,13 +159,9 @@ async function getPluginsSeparated(nxJson, root = workspace_root_1.workspaceRoot
|
|
|
152
159
|
if (pendingSeparatedPlugins?.hash === pluginsConfigurationHash) {
|
|
153
160
|
return pendingSeparatedPlugins.promise;
|
|
154
161
|
}
|
|
155
|
-
// Plugins config changed (e.g. `nx add @nx/maven`
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
// by the `??=` below and serve the previous plugin set forever. Tear
|
|
159
|
-
// down the old workers and force a fresh load.
|
|
160
|
-
cleanupSpecifiedPlugins?.();
|
|
161
|
-
pendingPluginsPromise = undefined;
|
|
162
|
+
// Plugins config changed (e.g. `nx add @nx/maven`): drop the in-flight load,
|
|
163
|
+
// or the `??=` below would serve the previous plugin set forever.
|
|
164
|
+
forgetSpecifiedPlugins();
|
|
162
165
|
const loadPromise = (async () => {
|
|
163
166
|
const results = await Promise.allSettled([
|
|
164
167
|
getOnlyDefaultPlugins(root),
|
|
@@ -188,7 +191,6 @@ async function getPluginsSeparated(nxJson, root = workspace_root_1.workspaceRoot
|
|
|
188
191
|
if (pendingSeparatedPlugins?.promise === loadPromise) {
|
|
189
192
|
cachedSeparatedPlugins = separatedPlugins;
|
|
190
193
|
currentPluginsConfigurationHash = pluginsConfigurationHash;
|
|
191
|
-
loadedPlugins = specifiedPlugins.concat(defaultPlugins);
|
|
192
194
|
}
|
|
193
195
|
return separatedPlugins;
|
|
194
196
|
})();
|
|
@@ -212,7 +214,6 @@ async function getPluginsSeparated(nxJson, root = workspace_root_1.workspaceRoot
|
|
|
212
214
|
*/
|
|
213
215
|
let loadedDefaultPlugins;
|
|
214
216
|
let loadedDefaultPluginsHash;
|
|
215
|
-
let cleanupDefaultPlugins;
|
|
216
217
|
let pendingDefaultPluginPromise;
|
|
217
218
|
async function getOnlyDefaultPlugins(root = workspace_root_1.workspaceRoot) {
|
|
218
219
|
const hash = root;
|
|
@@ -220,19 +221,15 @@ async function getOnlyDefaultPlugins(root = workspace_root_1.workspaceRoot) {
|
|
|
220
221
|
if (loadedDefaultPlugins && hash === loadedDefaultPluginsHash) {
|
|
221
222
|
return loadedDefaultPlugins;
|
|
222
223
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
224
|
+
const loadPromise = (pendingDefaultPluginPromise ??=
|
|
225
|
+
loadDefaultNxPlugins(workspace_root_1.workspaceRoot));
|
|
226
|
+
const result = await loadPromise;
|
|
227
|
+
// Commit only while this is still the registered load, so a set released while
|
|
228
|
+
// it was loading is not handed back out as the current one.
|
|
229
|
+
if (pendingDefaultPluginPromise === loadPromise) {
|
|
230
|
+
loadedDefaultPlugins = result;
|
|
231
|
+
loadedDefaultPluginsHash = hash;
|
|
226
232
|
}
|
|
227
|
-
pendingDefaultPluginPromise ??= loadDefaultNxPlugins(workspace_root_1.workspaceRoot);
|
|
228
|
-
const [result, cleanupFn] = await pendingDefaultPluginPromise;
|
|
229
|
-
cleanupDefaultPlugins = () => {
|
|
230
|
-
loadedDefaultPlugins = undefined;
|
|
231
|
-
pendingDefaultPluginPromise = undefined;
|
|
232
|
-
cleanupFn();
|
|
233
|
-
};
|
|
234
|
-
loadedDefaultPlugins = result;
|
|
235
|
-
loadedDefaultPluginsHash = hash;
|
|
236
233
|
return result;
|
|
237
234
|
}
|
|
238
235
|
/**
|
|
@@ -252,9 +249,9 @@ function getPluginsIfLoadedOrLoading() {
|
|
|
252
249
|
return Promise.resolve(separated).then(({ specifiedPlugins, defaultPlugins }) => specifiedPlugins.concat(defaultPlugins));
|
|
253
250
|
}
|
|
254
251
|
function cleanupPlugins() {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
252
|
+
(0, isolation_1.disposeIsolatedPlugins)();
|
|
253
|
+
forgetSpecifiedPlugins();
|
|
254
|
+
loadedDefaultPlugins = undefined;
|
|
258
255
|
pendingDefaultPluginPromise = undefined;
|
|
259
256
|
cachedSeparatedPlugins = undefined;
|
|
260
257
|
// Drop the in-flight load too: clearing the marker flips its commit gate to
|
|
@@ -264,19 +261,38 @@ function cleanupPlugins() {
|
|
|
264
261
|
/**
|
|
265
262
|
* Stuff for generic loading
|
|
266
263
|
*/
|
|
264
|
+
function pluginLabel(plugin) {
|
|
265
|
+
return typeof plugin === 'string' ? plugin : plugin.plugin;
|
|
266
|
+
}
|
|
267
|
+
async function loadPlugins(loader, pluginConfigurations, root, assignIndexes) {
|
|
268
|
+
const loads = pluginConfigurations.map((plugin, index) => ({
|
|
269
|
+
plugin,
|
|
270
|
+
index: assignIndexes ? index : undefined,
|
|
271
|
+
}));
|
|
272
|
+
(0, isolation_1.wantPlugins)(loader, loads, root);
|
|
273
|
+
return Promise.allSettled(loads.map(async ({ plugin, index }) => {
|
|
274
|
+
const label = pluginLabel(plugin);
|
|
275
|
+
performance.mark(`Load Nx Plugin: ${label} - start`);
|
|
276
|
+
const res = await (0, exports.loadingMethod)(plugin, root, index);
|
|
277
|
+
performance.mark(`Load Nx Plugin: ${label} - end`);
|
|
278
|
+
performance.measure(`Load Nx Plugin: ${label}`, `Load Nx Plugin: ${label} - start`, `Load Nx Plugin: ${label} - end`);
|
|
279
|
+
return res;
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
282
|
+
async function capabilitiesOfConfiguredPlugins(nxJson, root = workspace_root_1.workspaceRoot) {
|
|
283
|
+
if (!(0, is_on_daemon_1.isOnDaemon)() && (0, client_1.isDaemonEnabled)()) {
|
|
284
|
+
return client_1.daemonClient.getPluginCapabilities();
|
|
285
|
+
}
|
|
286
|
+
const recorded = (0, nx_plugin_capabilities_1.capabilitiesOfNxPluginsReadFromCache)();
|
|
287
|
+
if (recorded) {
|
|
288
|
+
return recorded;
|
|
289
|
+
}
|
|
290
|
+
return (await getPlugins(nxJson, root)).map((plugin) => plugin.capabilities());
|
|
291
|
+
}
|
|
267
292
|
async function loadDefaultNxPlugins(root = workspace_root_1.workspaceRoot) {
|
|
268
293
|
performance.mark('loadDefaultNxPlugins:start');
|
|
269
294
|
const plugins = getDefaultPlugins(root);
|
|
270
|
-
const
|
|
271
|
-
const results = await Promise.allSettled(plugins.map(async (plugin) => {
|
|
272
|
-
performance.mark(`Load Nx Plugin: ${plugin} - start`);
|
|
273
|
-
const [loadedPluginPromise, cleanup] = await (0, exports.loadingMethod)(plugin, root);
|
|
274
|
-
cleanupFunctions.push(cleanup);
|
|
275
|
-
const res = await loadedPluginPromise;
|
|
276
|
-
performance.mark(`Load Nx Plugin: ${plugin} - end`);
|
|
277
|
-
performance.measure(`Load Nx Plugin: ${plugin}`, `Load Nx Plugin: ${plugin} - start`, `Load Nx Plugin: ${plugin} - end`);
|
|
278
|
-
return res;
|
|
279
|
-
}));
|
|
295
|
+
const results = await loadPlugins('default', plugins, root, false);
|
|
280
296
|
const defaultPluginResults = [];
|
|
281
297
|
const errors = [];
|
|
282
298
|
for (let i = 0; i < results.length; i++) {
|
|
@@ -292,52 +308,25 @@ async function loadDefaultNxPlugins(root = workspace_root_1.workspaceRoot) {
|
|
|
292
308
|
}
|
|
293
309
|
}
|
|
294
310
|
if (errors.length > 0) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
311
|
+
// Cleared so the next call retries instead of re-awaiting this rejection.
|
|
312
|
+
pendingDefaultPluginPromise = undefined;
|
|
298
313
|
const errorMessage = errors
|
|
299
314
|
.map((e) => ` - ${e.pluginName}: ${e.error.message}`)
|
|
300
315
|
.join('\n');
|
|
301
316
|
throw new AggregateError(errors.map((e) => e.error), `Failed to load ${errors.length} default Nx plugin(s):\n${errorMessage}`);
|
|
302
317
|
}
|
|
303
|
-
const ret = [
|
|
304
|
-
defaultPluginResults,
|
|
305
|
-
() => {
|
|
306
|
-
for (const fn of cleanupFunctions) {
|
|
307
|
-
fn();
|
|
308
|
-
}
|
|
309
|
-
if ((0, transpiler_1.pluginTranspilerIsRegistered)()) {
|
|
310
|
-
(0, transpiler_1.cleanupPluginTSTranspiler)();
|
|
311
|
-
}
|
|
312
|
-
},
|
|
313
|
-
];
|
|
314
318
|
performance.mark('loadDefaultNxPlugins:end');
|
|
315
319
|
performance.measure('loadDefaultNxPlugins', 'loadDefaultNxPlugins:start', 'loadDefaultNxPlugins:end');
|
|
316
|
-
return
|
|
320
|
+
return defaultPluginResults;
|
|
317
321
|
}
|
|
318
322
|
async function loadSpecifiedNxPlugins(pluginsConfigurations, root = workspace_root_1.workspaceRoot) {
|
|
319
|
-
// Returning existing plugins is handled by getPlugins,
|
|
320
|
-
// so, if we are here and there are existing plugins, they are stale
|
|
321
|
-
if (cleanupSpecifiedPlugins) {
|
|
322
|
-
cleanupSpecifiedPlugins();
|
|
323
|
-
}
|
|
324
323
|
performance.mark('loadSpecifiedNxPlugins:start');
|
|
325
324
|
pluginsConfigurations ??= [];
|
|
326
325
|
// Drop the cached workspace-layout snapshot local-plugin resolution uses:
|
|
327
326
|
// in a long-lived daemon it can predate a newly added local plugin and
|
|
328
327
|
// resolve it to the workspace root. Runs only when the plugin set changed.
|
|
329
328
|
(0, resolve_plugin_1.resetResolvePluginCache)();
|
|
330
|
-
const
|
|
331
|
-
const results = await Promise.allSettled(pluginsConfigurations.map(async (plugin, index) => {
|
|
332
|
-
const pluginPath = typeof plugin === 'string' ? plugin : plugin.plugin;
|
|
333
|
-
performance.mark(`Load Nx Plugin: ${pluginPath} - start`);
|
|
334
|
-
const [loadedPluginPromise, cleanup] = await (0, exports.loadingMethod)(plugin, root, index);
|
|
335
|
-
cleanupFunctions.push(cleanup);
|
|
336
|
-
const res = await loadedPluginPromise;
|
|
337
|
-
performance.mark(`Load Nx Plugin: ${pluginPath} - end`);
|
|
338
|
-
performance.measure(`Load Nx Plugin: ${pluginPath}`, `Load Nx Plugin: ${pluginPath} - start`, `Load Nx Plugin: ${pluginPath} - end`);
|
|
339
|
-
return res;
|
|
340
|
-
}));
|
|
329
|
+
const results = await loadPlugins('specified', pluginsConfigurations, root, true);
|
|
341
330
|
performance.mark('loadSpecifiedNxPlugins:end');
|
|
342
331
|
performance.measure('loadSpecifiedNxPlugins', 'loadSpecifiedNxPlugins:start', 'loadSpecifiedNxPlugins:end');
|
|
343
332
|
const plugins = [];
|
|
@@ -357,23 +346,12 @@ async function loadSpecifiedNxPlugins(pluginsConfigurations, root = workspace_ro
|
|
|
357
346
|
}
|
|
358
347
|
}
|
|
359
348
|
if (errors.length > 0) {
|
|
360
|
-
|
|
361
|
-
fn();
|
|
362
|
-
}
|
|
349
|
+
// Wants are not retracted: a newer load may own the declaration by now.
|
|
363
350
|
const errorMessage = errors
|
|
364
351
|
.map((e) => ` - ${e.pluginName}: ${e.error.message}`)
|
|
365
352
|
.join('\n');
|
|
366
353
|
throw new AggregateError(errors.map((e) => e.error), `Failed to load ${errors.length} Nx plugin(s):\n${errorMessage}`);
|
|
367
354
|
}
|
|
368
|
-
cleanupSpecifiedPlugins = () => {
|
|
369
|
-
for (const fn of cleanupFunctions) {
|
|
370
|
-
fn();
|
|
371
|
-
}
|
|
372
|
-
if ((0, transpiler_1.pluginTranspilerIsRegistered)()) {
|
|
373
|
-
(0, transpiler_1.cleanupPluginTSTranspiler)();
|
|
374
|
-
}
|
|
375
|
-
pendingPluginsPromise = undefined;
|
|
376
|
-
};
|
|
377
355
|
return plugins;
|
|
378
356
|
}
|
|
379
357
|
function reasonToError(reason) {
|
|
@@ -6,5 +6,5 @@ export declare function readPluginPackageJson(pluginName: string, projects: Reco
|
|
|
6
6
|
path: string;
|
|
7
7
|
json: PackageJson;
|
|
8
8
|
};
|
|
9
|
-
export declare function loadNxPlugin(plugin: PluginConfiguration, root: string, index?: number):
|
|
9
|
+
export declare function loadNxPlugin(plugin: PluginConfiguration, root: string, index?: number): Promise<LoadedNxPlugin>;
|
|
10
10
|
export declare function loadNxPluginAsync(pluginConfiguration: PluginConfiguration, paths: string[], root: string, index?: number): Promise<LoadedNxPlugin>;
|
|
@@ -38,10 +38,7 @@ function readPluginPackageJson(pluginName, projects, paths = (0, installation_di
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
function loadNxPlugin(plugin, root, index) {
|
|
41
|
-
return
|
|
42
|
-
loadNxPluginAsync(plugin, (0, installation_directory_1.getNxRequirePaths)(root), root, index),
|
|
43
|
-
() => { },
|
|
44
|
-
];
|
|
41
|
+
return loadNxPluginAsync(plugin, (0, installation_directory_1.getNxRequirePaths)(root), root, index);
|
|
45
42
|
}
|
|
46
43
|
async function loadNxPluginAsync(pluginConfiguration, paths, root, index) {
|
|
47
44
|
const moduleName = typeof pluginConfiguration === 'string'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { loadIsolatedNxPlugin } from './load-isolated-plugin';
|
|
1
|
+
export { disposeIsolatedPlugins, loadIsolatedNxPlugin, wantPlugins, } from './load-isolated-plugin';
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.loadIsolatedNxPlugin = void 0;
|
|
3
|
+
exports.wantPlugins = exports.loadIsolatedNxPlugin = exports.disposeIsolatedPlugins = void 0;
|
|
4
4
|
var load_isolated_plugin_1 = require("./load-isolated-plugin");
|
|
5
|
+
Object.defineProperty(exports, "disposeIsolatedPlugins", { enumerable: true, get: function () { return load_isolated_plugin_1.disposeIsolatedPlugins; } });
|
|
5
6
|
Object.defineProperty(exports, "loadIsolatedNxPlugin", { enumerable: true, get: function () { return load_isolated_plugin_1.loadIsolatedNxPlugin; } });
|
|
7
|
+
Object.defineProperty(exports, "wantPlugins", { enumerable: true, get: function () { return load_isolated_plugin_1.wantPlugins; } });
|
|
@@ -4,6 +4,7 @@ import type { PluginConfiguration } from '../../../config/nx-json';
|
|
|
4
4
|
import type { ProjectGraph } from '../../../config/project-graph';
|
|
5
5
|
import type { RawProjectGraphDependency } from '../../project-graph-builder';
|
|
6
6
|
import { LoadedNxPlugin } from '../loaded-nx-plugin';
|
|
7
|
+
import type { NxPluginCapabilities } from '../nx-plugin-capabilities';
|
|
7
8
|
import type { CreateDependenciesContext, CreateMetadataContext, CreateNodesContext, CreateNodesResult, PostTasksExecutionContext, PreTasksExecutionContext, ProjectsMetadata } from '../public-api';
|
|
8
9
|
import type { PluginWorkerLoadResult } from './messaging';
|
|
9
10
|
import { Hook, Phase } from './plugin-lifecycle-manager';
|
|
@@ -26,6 +27,7 @@ export declare class IsolatedPlugin implements LoadedNxPlugin {
|
|
|
26
27
|
private worker;
|
|
27
28
|
private socket;
|
|
28
29
|
private _alive;
|
|
30
|
+
private _released;
|
|
29
31
|
private _connectPromise;
|
|
30
32
|
private txId;
|
|
31
33
|
private pendingCount;
|
|
@@ -41,6 +43,7 @@ export declare class IsolatedPlugin implements LoadedNxPlugin {
|
|
|
41
43
|
*/
|
|
42
44
|
static load(plugin: PluginConfiguration, root: string, index?: number): Promise<IsolatedPlugin>;
|
|
43
45
|
private constructor();
|
|
46
|
+
capabilities(): NxPluginCapabilities;
|
|
44
47
|
private spawnAndConnect;
|
|
45
48
|
/**
|
|
46
49
|
* Drops the worker from service without judging why. The next hook call
|
|
@@ -66,6 +69,11 @@ export declare class IsolatedPlugin implements LoadedNxPlugin {
|
|
|
66
69
|
private shutdownIfInactive;
|
|
67
70
|
setWorkerEnv(env: Record<string, string>): Promise<void>;
|
|
68
71
|
notifyPhaseAborted(phase: Phase, lastCompletedHook: Hook): void;
|
|
72
|
+
/**
|
|
73
|
+
* Like `shutdown`, but for good: a later hook call still answers, then shuts
|
|
74
|
+
* the worker back down instead of leaving a respawned one running.
|
|
75
|
+
*/
|
|
76
|
+
dispose(): void;
|
|
69
77
|
shutdown(): void;
|
|
70
78
|
private registerProcessMetrics;
|
|
71
79
|
}
|
|
@@ -44,9 +44,16 @@ class IsolatedPlugin {
|
|
|
44
44
|
const moduleName = typeof plugin === 'string' ? plugin : plugin.plugin;
|
|
45
45
|
const { name, pluginPath, shouldRegisterTSTranspiler } = await (0, resolve_plugin_1.resolveNxPlugin)(moduleName, root, (0, installation_directory_1.getNxRequirePaths)(root));
|
|
46
46
|
const instance = new IsolatedPlugin(plugin, root, name, pluginPath, shouldRegisterTSTranspiler, index);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
try {
|
|
48
|
+
const loadResult = await instance.spawnAndConnect();
|
|
49
|
+
instance.setupHooks(loadResult);
|
|
50
|
+
return instance;
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
// A timed-out worker is still running, and the caller is about to drop this instance.
|
|
54
|
+
instance.shutdown();
|
|
55
|
+
throw e;
|
|
56
|
+
}
|
|
50
57
|
}
|
|
51
58
|
constructor(plugin, root, name, pluginPath, shouldRegisterTSTranspiler, index) {
|
|
52
59
|
this.index = index;
|
|
@@ -54,6 +61,7 @@ class IsolatedPlugin {
|
|
|
54
61
|
this.worker = null;
|
|
55
62
|
this.socket = null;
|
|
56
63
|
this._alive = false;
|
|
64
|
+
this._released = false;
|
|
57
65
|
this._connectPromise = null;
|
|
58
66
|
this.txId = 0;
|
|
59
67
|
this.pendingCount = 0;
|
|
@@ -91,6 +99,15 @@ class IsolatedPlugin {
|
|
|
91
99
|
this.pluginPath = pluginPath;
|
|
92
100
|
this.shouldRegisterTSTranspiler = shouldRegisterTSTranspiler;
|
|
93
101
|
}
|
|
102
|
+
capabilities() {
|
|
103
|
+
return {
|
|
104
|
+
createNodesPattern: this.createNodes?.[0],
|
|
105
|
+
hasCreateDependencies: !!this.createDependencies,
|
|
106
|
+
hasCreateMetadata: !!this.createMetadata,
|
|
107
|
+
hasPreTasksExecution: !!this.preTasksExecution,
|
|
108
|
+
hasPostTasksExecution: !!this.postTasksExecution,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
94
111
|
async spawnAndConnect() {
|
|
95
112
|
const { worker, socket } = await startPluginWorker(this.name);
|
|
96
113
|
this.worker = worker;
|
|
@@ -215,7 +232,15 @@ class IsolatedPlugin {
|
|
|
215
232
|
const shutdown = (hookName) => this.shutdownIfInactive(hookName);
|
|
216
233
|
const wrap = (hook, hookFn) => this.lifecycle.wrapHook(hook, async (...args) => {
|
|
217
234
|
await this.ensureAlive();
|
|
218
|
-
|
|
235
|
+
try {
|
|
236
|
+
return await hookFn(...args);
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
// A released plugin still answers, then shuts its worker straight back down.
|
|
240
|
+
if (this._released) {
|
|
241
|
+
shutdown(hook);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
219
244
|
}, () => shutdown(hook));
|
|
220
245
|
if (loadResult.createNodesPattern) {
|
|
221
246
|
this.createNodes = [
|
|
@@ -339,8 +364,18 @@ class IsolatedPlugin {
|
|
|
339
364
|
this.shutdownIfInactive(lastCompletedHook);
|
|
340
365
|
}
|
|
341
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Like `shutdown`, but for good: a later hook call still answers, then shuts
|
|
369
|
+
* the worker back down instead of leaving a respawned one running.
|
|
370
|
+
*/
|
|
371
|
+
dispose() {
|
|
372
|
+
this._released = true;
|
|
373
|
+
this.shutdown();
|
|
374
|
+
}
|
|
342
375
|
shutdown() {
|
|
343
|
-
|
|
376
|
+
// Not `_alive`: that is only set once the worker answers a load, so gating
|
|
377
|
+
// on it would leave a worker that never got that far running.
|
|
378
|
+
if (!this.worker && !this.socket)
|
|
344
379
|
return;
|
|
345
380
|
this._alive = false;
|
|
346
381
|
this._connectPromise = null;
|
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
import { PluginConfiguration } from '../../../config/nx-json';
|
|
2
2
|
import type { LoadedNxPlugin } from '../loaded-nx-plugin';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Declares a loader's plugins and disposes any no loader wants. Call before loading.
|
|
5
|
+
* Anything that makes a running worker unfit for reuse must be in its cache key.
|
|
6
|
+
*/
|
|
7
|
+
export declare function wantPlugins(loader: string, plugins: Array<{
|
|
8
|
+
plugin: PluginConfiguration;
|
|
9
|
+
index?: number;
|
|
10
|
+
}>, root: string): void;
|
|
11
|
+
export declare function disposeIsolatedPlugins(): void;
|
|
12
|
+
export declare function loadIsolatedNxPlugin(plugin: PluginConfiguration, root: string, index?: number): Promise<LoadedNxPlugin>;
|
|
@@ -1,24 +1,74 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wantPlugins = wantPlugins;
|
|
4
|
+
exports.disposeIsolatedPlugins = disposeIsolatedPlugins;
|
|
3
5
|
exports.loadIsolatedNxPlugin = loadIsolatedNxPlugin;
|
|
4
6
|
const isolated_plugin_1 = require("./isolated-plugin");
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
const loadedPlugins = (global['nxLoadedPlugins'] ??= new Map());
|
|
8
|
+
/**
|
|
9
|
+
* Keys each loader last asked for; a sweep keeps their union. Global like
|
|
10
|
+
* `loadedPlugins`, or one copy of Nx would sweep another's workers.
|
|
11
|
+
*/
|
|
12
|
+
const wantedBy = (global['nxWantedPlugins'] ??=
|
|
13
|
+
new Map());
|
|
14
|
+
/**
|
|
15
|
+
* Declares a loader's plugins and disposes any no loader wants. Call before loading.
|
|
16
|
+
* Anything that makes a running worker unfit for reuse must be in its cache key.
|
|
17
|
+
*/
|
|
18
|
+
function wantPlugins(loader, plugins, root) {
|
|
19
|
+
wantedBy.set(loader, new Set(plugins.map(({ plugin, index }) => getCacheKey(plugin, root, index))));
|
|
20
|
+
sweep();
|
|
21
|
+
}
|
|
22
|
+
function disposeIsolatedPlugins() {
|
|
23
|
+
wantedBy.clear();
|
|
24
|
+
sweep();
|
|
25
|
+
}
|
|
26
|
+
function loadIsolatedNxPlugin(plugin, root, index) {
|
|
27
|
+
const cacheKey = getCacheKey(plugin, root, index);
|
|
28
|
+
return (loadedPlugins.get(cacheKey) ??
|
|
29
|
+
register(cacheKey, isolated_plugin_1.IsolatedPlugin.load(plugin, root, index)));
|
|
30
|
+
}
|
|
31
|
+
function register(cacheKey, loading) {
|
|
32
|
+
const entry = loading.then((plugin) => {
|
|
33
|
+
// Swept while loading: nothing names it any more.
|
|
34
|
+
if (!isWanted(cacheKey)) {
|
|
35
|
+
plugin.dispose();
|
|
36
|
+
}
|
|
37
|
+
return plugin;
|
|
38
|
+
}, (err) => {
|
|
39
|
+
forget(cacheKey, entry);
|
|
14
40
|
throw err;
|
|
15
41
|
});
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
42
|
+
if (isWanted(cacheKey)) {
|
|
43
|
+
loadedPlugins.set(cacheKey, entry);
|
|
44
|
+
}
|
|
45
|
+
return entry;
|
|
46
|
+
}
|
|
47
|
+
function sweep() {
|
|
48
|
+
for (const [cacheKey, entry] of [...loadedPlugins]) {
|
|
49
|
+
if (isWanted(cacheKey)) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
loadedPlugins.delete(cacheKey);
|
|
53
|
+
entry.then((plugin) => plugin.dispose(),
|
|
54
|
+
// No worker to dispose; the caller reports the rejection.
|
|
55
|
+
() => { });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function isWanted(cacheKey) {
|
|
59
|
+
for (const keys of wantedBy.values()) {
|
|
60
|
+
if (keys.has(cacheKey)) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
/** Includes the index: a plugin carries its nx.json position, which exclusions and errors point at. */
|
|
67
|
+
function getCacheKey(plugin, root, index) {
|
|
68
|
+
return JSON.stringify({ plugin, root, index });
|
|
69
|
+
}
|
|
70
|
+
function forget(cacheKey, entry) {
|
|
71
|
+
if (loadedPlugins.get(cacheKey) === entry) {
|
|
72
|
+
loadedPlugins.delete(cacheKey);
|
|
73
|
+
}
|
|
24
74
|
}
|
|
@@ -3,6 +3,7 @@ import { type PluginConfiguration } from '../../config/nx-json';
|
|
|
3
3
|
import type { RawProjectGraphDependency } from '../project-graph-builder';
|
|
4
4
|
import type { CreateDependenciesContext, CreateMetadataContext, CreateNodesContext, CreateNodesResult, NxPlugin, PreTasksExecutionContext, ProjectsMetadata } from './public-api';
|
|
5
5
|
import { type MaybeStubbedPostTasksExecutionContext } from './task-results-stub';
|
|
6
|
+
import type { NxPluginCapabilities } from './nx-plugin-capabilities';
|
|
6
7
|
/**
|
|
7
8
|
* NOTE: Avoid using `import type` with this class. It causes issues with
|
|
8
9
|
* jest's module resolution when running tests in projects that import
|
|
@@ -39,4 +40,5 @@ export declare class LoadedNxPlugin {
|
|
|
39
40
|
*/
|
|
40
41
|
setWorkerEnv?(env: Record<string, string>): Promise<void>;
|
|
41
42
|
constructor(plugin: NxPlugin, pluginDefinition: PluginConfiguration, index?: number);
|
|
43
|
+
capabilities(): NxPluginCapabilities;
|
|
42
44
|
}
|
|
@@ -104,5 +104,14 @@ class LoadedNxPlugin {
|
|
|
104
104
|
this.postTasksExecution = async (context) => plugin.postTasksExecution(this.options, await (0, task_results_stub_1.rehydrateTerminalOutputs)(context));
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
+
capabilities() {
|
|
108
|
+
return {
|
|
109
|
+
createNodesPattern: this.createNodes?.[0],
|
|
110
|
+
hasCreateDependencies: !!this.createDependencies,
|
|
111
|
+
hasCreateMetadata: !!this.createMetadata,
|
|
112
|
+
hasPreTasksExecution: !!this.preTasksExecution,
|
|
113
|
+
hasPostTasksExecution: !!this.postTasksExecution,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
107
116
|
}
|
|
108
117
|
exports.LoadedNxPlugin = LoadedNxPlugin;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type CachedPluginCapabilities, NxPluginCapabilities as NxPluginCapabilitiesStore } from '../../native';
|
|
2
|
+
export type NxPluginCapabilities = CachedPluginCapabilities;
|
|
3
|
+
export declare function getNxPluginCapabilitiesStore(): NxPluginCapabilitiesStore | null;
|
|
4
|
+
export declare function noteGraphReadFromCache(computedAt: number | undefined): void;
|
|
5
|
+
/** Null means "load them", never "no plugin registers anything". */
|
|
6
|
+
export declare function capabilitiesOfNxPluginsReadFromCache(): NxPluginCapabilities[] | null;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getNxPluginCapabilitiesStore = getNxPluginCapabilitiesStore;
|
|
4
|
+
exports.noteGraphReadFromCache = noteGraphReadFromCache;
|
|
5
|
+
exports.capabilitiesOfNxPluginsReadFromCache = capabilitiesOfNxPluginsReadFromCache;
|
|
6
|
+
const native_1 = require("../../native");
|
|
7
|
+
const db_connection_1 = require("../../utils/db-connection");
|
|
8
|
+
let store;
|
|
9
|
+
function getNxPluginCapabilitiesStore() {
|
|
10
|
+
// The database is not part of the WASM build.
|
|
11
|
+
if (native_1.IS_WASM) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
// Checkout-local: the rows describe this checkout's graph.
|
|
15
|
+
store ??= new native_1.NxPluginCapabilities((0, db_connection_1.getLocalDbConnection)());
|
|
16
|
+
return store;
|
|
17
|
+
}
|
|
18
|
+
let computedAtOfGraphReadFromCache;
|
|
19
|
+
function noteGraphReadFromCache(computedAt) {
|
|
20
|
+
computedAtOfGraphReadFromCache = computedAt;
|
|
21
|
+
}
|
|
22
|
+
/** Null means "load them", never "no plugin registers anything". */
|
|
23
|
+
function capabilitiesOfNxPluginsReadFromCache() {
|
|
24
|
+
if (computedAtOfGraphReadFromCache === undefined) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return (getNxPluginCapabilitiesStore()?.get(computedAtOfGraphReadFromCache) ?? null);
|
|
28
|
+
}
|
|
@@ -8,8 +8,17 @@ const is_on_daemon_1 = require("../../daemon/is-on-daemon");
|
|
|
8
8
|
const client_1 = require("../../daemon/client/client");
|
|
9
9
|
const workspace_root_1 = require("../../utils/workspace-root");
|
|
10
10
|
const task_results_stub_1 = require("./task-results-stub");
|
|
11
|
+
const nx_plugin_capabilities_1 = require("./nx-plugin-capabilities");
|
|
12
|
+
/** True only when the cached graph's recorded rows show no plugin has `hook`; unknown is false. */
|
|
13
|
+
function knownThatNoPluginRegisters(hook) {
|
|
14
|
+
const recorded = (0, nx_plugin_capabilities_1.capabilitiesOfNxPluginsReadFromCache)();
|
|
15
|
+
return !!recorded && !recorded.some((capabilities) => capabilities[hook]);
|
|
16
|
+
}
|
|
11
17
|
async function runPreTasksExecution(pluginContext) {
|
|
12
18
|
if ((0, is_on_daemon_1.isOnDaemon)() || !(0, client_1.isDaemonEnabled)()) {
|
|
19
|
+
if (knownThatNoPluginRegisters('hasPreTasksExecution')) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
13
22
|
performance.mark(`preTasksExecution:start`);
|
|
14
23
|
const plugins = await (0, get_plugins_1.getPlugins)((0, nx_json_1.readNxJson)(pluginContext.workspaceRoot), pluginContext.workspaceRoot);
|
|
15
24
|
const envs = await Promise.all(plugins
|
|
@@ -45,6 +54,9 @@ function applyProcessEnvs(envs) {
|
|
|
45
54
|
}
|
|
46
55
|
async function runPostTasksExecution(context) {
|
|
47
56
|
if ((0, is_on_daemon_1.isOnDaemon)() || !(0, client_1.isDaemonEnabled)()) {
|
|
57
|
+
if (knownThatNoPluginRegisters('hasPostTasksExecution')) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
48
60
|
performance.mark(`postTasksExecution:start`);
|
|
49
61
|
const plugins = await (0, get_plugins_1.getPlugins)((0, nx_json_1.readNxJson)(workspace_root_1.workspaceRoot));
|
|
50
62
|
await Promise.all(plugins
|