nx 18.1.0-canary.20240227-452d845 → 18.1.0-canary.20240229-f6a183c
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/package.json +12 -12
- package/src/daemon/server/project-graph-incremental-recomputation.js +4 -1
- package/src/migrations/update-15-1-0/set-project-names.js +2 -0
- package/src/project-graph/build-project-graph.js +3 -5
- package/src/project-graph/plugins/internal-api.d.ts +2 -5
- package/src/project-graph/plugins/internal-api.js +5 -41
- package/src/project-graph/plugins/messaging.d.ts +10 -5
- package/src/project-graph/plugins/plugin-pool.d.ts +1 -1
- package/src/project-graph/plugins/plugin-pool.js +94 -66
- package/src/project-graph/plugins/plugin-worker.js +22 -29
- package/src/project-graph/plugins/utils.d.ts +9 -0
- package/src/project-graph/plugins/utils.js +55 -0
- package/src/project-graph/plugins/worker-api.js +2 -2
- package/src/project-graph/project-graph.js +2 -0
- package/src/project-graph/utils/project-configuration-utils.js +10 -27
- package/src/project-graph/utils/retrieve-workspace-files.js +6 -1
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "nx",
|
3
|
-
"version": "18.1.0-canary.
|
3
|
+
"version": "18.1.0-canary.20240229-f6a183c",
|
4
4
|
"private": false,
|
5
5
|
"description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
|
6
6
|
"repository": {
|
@@ -66,7 +66,7 @@
|
|
66
66
|
"yargs-parser": "21.1.1",
|
67
67
|
"node-machine-id": "1.1.12",
|
68
68
|
"ora": "5.3.0",
|
69
|
-
"@nrwl/tao": "18.1.0-canary.
|
69
|
+
"@nrwl/tao": "18.1.0-canary.20240229-f6a183c"
|
70
70
|
},
|
71
71
|
"peerDependencies": {
|
72
72
|
"@swc-node/register": "^1.8.0",
|
@@ -81,16 +81,16 @@
|
|
81
81
|
}
|
82
82
|
},
|
83
83
|
"optionalDependencies": {
|
84
|
-
"@nx/nx-darwin-x64": "18.1.0-canary.
|
85
|
-
"@nx/nx-darwin-arm64": "18.1.0-canary.
|
86
|
-
"@nx/nx-linux-x64-gnu": "18.1.0-canary.
|
87
|
-
"@nx/nx-linux-x64-musl": "18.1.0-canary.
|
88
|
-
"@nx/nx-win32-x64-msvc": "18.1.0-canary.
|
89
|
-
"@nx/nx-linux-arm64-gnu": "18.1.0-canary.
|
90
|
-
"@nx/nx-linux-arm64-musl": "18.1.0-canary.
|
91
|
-
"@nx/nx-linux-arm-gnueabihf": "18.1.0-canary.
|
92
|
-
"@nx/nx-win32-arm64-msvc": "18.1.0-canary.
|
93
|
-
"@nx/nx-freebsd-x64": "18.1.0-canary.
|
84
|
+
"@nx/nx-darwin-x64": "18.1.0-canary.20240229-f6a183c",
|
85
|
+
"@nx/nx-darwin-arm64": "18.1.0-canary.20240229-f6a183c",
|
86
|
+
"@nx/nx-linux-x64-gnu": "18.1.0-canary.20240229-f6a183c",
|
87
|
+
"@nx/nx-linux-x64-musl": "18.1.0-canary.20240229-f6a183c",
|
88
|
+
"@nx/nx-win32-x64-msvc": "18.1.0-canary.20240229-f6a183c",
|
89
|
+
"@nx/nx-linux-arm64-gnu": "18.1.0-canary.20240229-f6a183c",
|
90
|
+
"@nx/nx-linux-arm64-musl": "18.1.0-canary.20240229-f6a183c",
|
91
|
+
"@nx/nx-linux-arm-gnueabihf": "18.1.0-canary.20240229-f6a183c",
|
92
|
+
"@nx/nx-win32-arm64-msvc": "18.1.0-canary.20240229-f6a183c",
|
93
|
+
"@nx/nx-freebsd-x64": "18.1.0-canary.20240229-f6a183c"
|
94
94
|
},
|
95
95
|
"nx-migrations": {
|
96
96
|
"migrations": "./migrations.json",
|
@@ -137,9 +137,12 @@ async function processFilesAndCreateAndSerializeProjectGraph() {
|
|
137
137
|
logger_1.serverLogger.requestLog([...updatedFiles.values()]);
|
138
138
|
logger_1.serverLogger.requestLog([...deletedFiles]);
|
139
139
|
const nxJson = (0, nx_json_1.readNxJson)(workspace_root_1.workspaceRoot);
|
140
|
+
global.NX_GRAPH_CREATION = true;
|
140
141
|
const graphNodes = await (0, retrieve_workspace_files_1.retrieveProjectConfigurations)(workspace_root_1.workspaceRoot, nxJson);
|
141
142
|
await processCollectedUpdatedAndDeletedFiles(graphNodes, updatedFileHashes, deletedFiles);
|
142
|
-
|
143
|
+
const g = createAndSerializeProjectGraph(graphNodes);
|
144
|
+
delete global.NX_GRAPH_CREATION;
|
145
|
+
return g;
|
143
146
|
}
|
144
147
|
catch (err) {
|
145
148
|
return Promise.resolve({
|
@@ -6,9 +6,11 @@ const json_1 = require("../../generators/utils/json");
|
|
6
6
|
const format_changed_files_with_prettier_if_available_1 = require("../../generators/internal-utils/format-changed-files-with-prettier-if-available");
|
7
7
|
const retrieve_workspace_files_1 = require("../../project-graph/utils/retrieve-workspace-files");
|
8
8
|
const internal_api_1 = require("../../project-graph/plugins/internal-api");
|
9
|
+
const plugin_pool_1 = require("../../project-graph/plugins/plugin-pool");
|
9
10
|
async function default_1(tree) {
|
10
11
|
const nxJson = (0, nx_json_1.readNxJson)(tree);
|
11
12
|
const projectFiles = await (0, retrieve_workspace_files_1.retrieveProjectConfigurationPaths)(tree.root, await (0, internal_api_1.loadNxPlugins)(nxJson?.plugins));
|
13
|
+
await (0, plugin_pool_1.shutdownPluginWorkers)();
|
12
14
|
const projectJsons = projectFiles.filter((f) => f.endsWith('project.json'));
|
13
15
|
for (let f of projectJsons) {
|
14
16
|
const projectJson = (0, json_1.readJson)(tree, f);
|
@@ -9,6 +9,7 @@ const nx_deps_cache_1 = require("./nx-deps-cache");
|
|
9
9
|
const implicit_project_dependencies_1 = require("./utils/implicit-project-dependencies");
|
10
10
|
const normalize_project_nodes_1 = require("./utils/normalize-project-nodes");
|
11
11
|
const internal_api_1 = require("./plugins/internal-api");
|
12
|
+
const utils_1 = require("./plugins/utils");
|
12
13
|
const typescript_1 = require("../plugins/js/utils/typescript");
|
13
14
|
const fileutils_1 = require("../utils/fileutils");
|
14
15
|
const project_graph_builder_1 = require("./project-graph-builder");
|
@@ -145,7 +146,7 @@ async function updateProjectGraphWithPlugins(context, initProjectGraph) {
|
|
145
146
|
let graph = initProjectGraph;
|
146
147
|
for (const plugin of plugins) {
|
147
148
|
try {
|
148
|
-
if ((0,
|
149
|
+
if ((0, utils_1.isNxPluginV1)(plugin) &&
|
149
150
|
plugin.processProjectGraph &&
|
150
151
|
!plugin.createDependencies) {
|
151
152
|
output_1.output.warn({
|
@@ -183,11 +184,9 @@ async function updateProjectGraphWithPlugins(context, initProjectGraph) {
|
|
183
184
|
}
|
184
185
|
}
|
185
186
|
const builder = new project_graph_builder_1.ProjectGraphBuilder(graph, context.fileMap.projectFileMap, context.fileMap.nonProjectFiles);
|
186
|
-
const createDependencyPlugins = plugins.filter((plugin) => (0,
|
187
|
+
const createDependencyPlugins = plugins.filter((plugin) => (0, utils_1.isNxPluginV2)(plugin) && plugin.createDependencies);
|
187
188
|
await Promise.all(createDependencyPlugins.map(async (plugin) => {
|
188
189
|
perf_hooks_1.performance.mark(`${plugin.name}:createDependencies - start`);
|
189
|
-
// Set this globally to allow plugins to know if they are being called from the project graph creation
|
190
|
-
global.NX_GRAPH_CREATION = true;
|
191
190
|
try {
|
192
191
|
// TODO: we shouldn't have to pass null here
|
193
192
|
const dependencies = await plugin.createDependencies(null, {
|
@@ -205,7 +204,6 @@ async function updateProjectGraphWithPlugins(context, initProjectGraph) {
|
|
205
204
|
}
|
206
205
|
throw new Error(message);
|
207
206
|
}
|
208
|
-
delete global.NX_GRAPH_CREATION;
|
209
207
|
perf_hooks_1.performance.mark(`${plugin.name}:createDependencies - end`);
|
210
208
|
perf_hooks_1.performance.measure(`${plugin.name}:createDependencies`, `${plugin.name}:createDependencies - start`, `${plugin.name}:createDependencies - end`);
|
211
209
|
}));
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { PluginConfiguration } from '../../config/nx-json';
|
2
2
|
import { NxPluginV1 } from '../../utils/nx-plugin.deprecated';
|
3
|
-
import { CreateNodesContext, CreateNodesResult,
|
3
|
+
import { CreateNodesContext, CreateNodesResult, NxPluginV2 } from './public-api';
|
4
4
|
export type CreateNodesResultWithContext = CreateNodesResult & {
|
5
5
|
file: string;
|
6
6
|
pluginName: string;
|
@@ -12,10 +12,7 @@ export type RemotePlugin = Omit<NormalizedPlugin, 'createNodes'> & {
|
|
12
12
|
fn: (matchedFiles: string[], context: CreateNodesContext) => Promise<CreateNodesResultWithContext[]>
|
13
13
|
];
|
14
14
|
};
|
15
|
-
export declare const nxPluginCache: Map<unknown, RemotePlugin
|
15
|
+
export declare const nxPluginCache: Map<unknown, Promise<RemotePlugin>>;
|
16
16
|
export declare function loadNxPlugins(plugins: PluginConfiguration[], root?: string): Promise<RemotePlugin[]>;
|
17
17
|
export declare function loadNxPlugin(plugin: PluginConfiguration, root?: string): Promise<RemotePlugin>;
|
18
|
-
export declare function isNxPluginV2(plugin: NxPlugin): plugin is NxPluginV2;
|
19
|
-
export declare function isNxPluginV1(plugin: NxPlugin | RemotePlugin): plugin is NxPluginV1;
|
20
|
-
export declare function normalizeNxPlugin(plugin: NxPlugin): NormalizedPlugin;
|
21
18
|
export declare function getDefaultPlugins(root: string): Promise<string[]>;
|
@@ -2,10 +2,8 @@
|
|
2
2
|
// This file contains the bits and bobs of the internal API for loading and interacting with Nx plugins.
|
3
3
|
// For the public API, used by plugin authors, see `./public-api.ts`.
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
5
|
-
exports.getDefaultPlugins = exports.
|
5
|
+
exports.getDefaultPlugins = exports.loadNxPlugin = exports.loadNxPlugins = exports.nxPluginCache = void 0;
|
6
6
|
const path_1 = require("path");
|
7
|
-
const workspaces_1 = require("../../config/workspaces");
|
8
|
-
const globs_1 = require("../../utils/globs");
|
9
7
|
const workspace_root_1 = require("../../utils/workspace-root");
|
10
8
|
const angular_json_1 = require("../../adapter/angular-json");
|
11
9
|
const plugin_pool_1 = require("./plugin-pool");
|
@@ -29,47 +27,13 @@ exports.loadNxPlugins = loadNxPlugins;
|
|
29
27
|
async function loadNxPlugin(plugin, root = workspace_root_1.workspaceRoot) {
|
30
28
|
const cacheKey = JSON.stringify(plugin);
|
31
29
|
if (exports.nxPluginCache.has(cacheKey)) {
|
32
|
-
return exports.nxPluginCache.get(cacheKey);
|
30
|
+
return await exports.nxPluginCache.get(cacheKey);
|
33
31
|
}
|
34
|
-
const
|
35
|
-
exports.nxPluginCache.set(cacheKey,
|
36
|
-
return
|
32
|
+
const loadingPlugin = (0, plugin_pool_1.loadRemoteNxPlugin)(plugin, root);
|
33
|
+
exports.nxPluginCache.set(cacheKey, loadingPlugin);
|
34
|
+
return await loadingPlugin;
|
37
35
|
}
|
38
36
|
exports.loadNxPlugin = loadNxPlugin;
|
39
|
-
function isNxPluginV2(plugin) {
|
40
|
-
return 'createNodes' in plugin || 'createDependencies' in plugin;
|
41
|
-
}
|
42
|
-
exports.isNxPluginV2 = isNxPluginV2;
|
43
|
-
function isNxPluginV1(plugin) {
|
44
|
-
return 'processProjectGraph' in plugin || 'projectFilePatterns' in plugin;
|
45
|
-
}
|
46
|
-
exports.isNxPluginV1 = isNxPluginV1;
|
47
|
-
function normalizeNxPlugin(plugin) {
|
48
|
-
if (isNxPluginV2(plugin)) {
|
49
|
-
return plugin;
|
50
|
-
}
|
51
|
-
if (isNxPluginV1(plugin) && plugin.projectFilePatterns) {
|
52
|
-
return {
|
53
|
-
...plugin,
|
54
|
-
createNodes: [
|
55
|
-
`*/**/${(0, globs_1.combineGlobPatterns)(plugin.projectFilePatterns)}`,
|
56
|
-
(configFilePath) => {
|
57
|
-
const root = (0, path_1.dirname)(configFilePath);
|
58
|
-
return {
|
59
|
-
projects: {
|
60
|
-
[root]: {
|
61
|
-
name: (0, workspaces_1.toProjectName)(configFilePath),
|
62
|
-
targets: plugin.registerProjectTargets?.(configFilePath),
|
63
|
-
},
|
64
|
-
},
|
65
|
-
};
|
66
|
-
},
|
67
|
-
],
|
68
|
-
};
|
69
|
-
}
|
70
|
-
return plugin;
|
71
|
-
}
|
72
|
-
exports.normalizeNxPlugin = normalizeNxPlugin;
|
73
37
|
async function getDefaultPlugins(root) {
|
74
38
|
return [
|
75
39
|
(0, path_1.join)(__dirname, '../../plugins/js'),
|
@@ -22,15 +22,12 @@ export interface PluginWorkerLoadResult {
|
|
22
22
|
error: string;
|
23
23
|
};
|
24
24
|
}
|
25
|
-
export interface PluginWorkerShutdownMessage {
|
26
|
-
type: 'shutdown';
|
27
|
-
payload: undefined;
|
28
|
-
}
|
29
25
|
export interface PluginWorkerCreateNodesMessage {
|
30
26
|
type: 'createNodes';
|
31
27
|
payload: {
|
32
28
|
configFiles: string[];
|
33
29
|
context: CreateNodesContext;
|
30
|
+
tx: string;
|
34
31
|
};
|
35
32
|
}
|
36
33
|
export interface PluginWorkerCreateNodesResult {
|
@@ -38,15 +35,18 @@ export interface PluginWorkerCreateNodesResult {
|
|
38
35
|
payload: {
|
39
36
|
success: true;
|
40
37
|
result: Awaited<ReturnType<RemotePlugin['createNodes'][1]>>;
|
38
|
+
tx: string;
|
41
39
|
} | {
|
42
40
|
success: false;
|
43
41
|
error: string;
|
42
|
+
tx: string;
|
44
43
|
};
|
45
44
|
}
|
46
45
|
export interface PluginCreateDependenciesMessage {
|
47
46
|
type: 'createDependencies';
|
48
47
|
payload: {
|
49
48
|
context: CreateDependenciesContext;
|
49
|
+
tx: string;
|
50
50
|
};
|
51
51
|
}
|
52
52
|
export interface PluginCreateDependenciesResult {
|
@@ -54,9 +54,11 @@ export interface PluginCreateDependenciesResult {
|
|
54
54
|
payload: {
|
55
55
|
dependencies: ReturnType<RemotePlugin['createDependencies']>;
|
56
56
|
success: true;
|
57
|
+
tx: string;
|
57
58
|
} | {
|
58
59
|
success: false;
|
59
60
|
error: string;
|
61
|
+
tx: string;
|
60
62
|
};
|
61
63
|
}
|
62
64
|
export interface PluginWorkerProcessProjectGraphMessage {
|
@@ -64,6 +66,7 @@ export interface PluginWorkerProcessProjectGraphMessage {
|
|
64
66
|
payload: {
|
65
67
|
graph: ProjectGraph;
|
66
68
|
ctx: ProjectGraphProcessorContext;
|
69
|
+
tx: string;
|
67
70
|
};
|
68
71
|
}
|
69
72
|
export interface PluginWorkerProcessProjectGraphResult {
|
@@ -71,12 +74,14 @@ export interface PluginWorkerProcessProjectGraphResult {
|
|
71
74
|
payload: {
|
72
75
|
graph: ProjectGraph;
|
73
76
|
success: true;
|
77
|
+
tx: string;
|
74
78
|
} | {
|
75
79
|
success: false;
|
76
80
|
error: string;
|
81
|
+
tx: string;
|
77
82
|
};
|
78
83
|
}
|
79
|
-
export type PluginWorkerMessage = PluginWorkerLoadMessage |
|
84
|
+
export type PluginWorkerMessage = PluginWorkerLoadMessage | PluginWorkerCreateNodesMessage | PluginCreateDependenciesMessage | PluginWorkerProcessProjectGraphMessage;
|
80
85
|
export type PluginWorkerResult = PluginWorkerLoadResult | PluginWorkerCreateNodesResult | PluginCreateDependenciesResult | PluginWorkerProcessProjectGraphResult;
|
81
86
|
type MaybePromise<T> = T | Promise<T>;
|
82
87
|
type MessageHandlerReturn<T extends PluginWorkerMessage | PluginWorkerResult> = T extends PluginWorkerResult ? MaybePromise<PluginWorkerMessage | void> : MaybePromise<PluginWorkerResult | void>;
|
@@ -1,4 +1,4 @@
|
|
1
1
|
import { PluginConfiguration } from '../../config/nx-json';
|
2
2
|
import { RemotePlugin } from './internal-api';
|
3
3
|
export declare function loadRemoteNxPlugin(plugin: PluginConfiguration, root: string): Promise<RemotePlugin>;
|
4
|
-
export declare function shutdownPluginWorkers(): Promise<
|
4
|
+
export declare function shutdownPluginWorkers(): Promise<void>;
|
@@ -3,11 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.shutdownPluginWorkers = exports.loadRemoteNxPlugin = void 0;
|
4
4
|
const child_process_1 = require("child_process");
|
5
5
|
const path = require("path");
|
6
|
-
|
6
|
+
// TODO (@AgentEnder): After scoped verbose logging is implemented, re-add verbose logs here.
|
7
|
+
// import { logger } from '../../utils/logger';
|
7
8
|
const internal_api_1 = require("./internal-api");
|
8
9
|
const messaging_1 = require("./messaging");
|
9
|
-
const pool =
|
10
|
+
const pool = new Set();
|
10
11
|
const pidMap = new Map();
|
12
|
+
// transaction id (tx) -> Promise, Resolver, Rejecter
|
13
|
+
// Makes sure that we can resolve the correct promise when the worker sends back the result
|
14
|
+
const promiseBank = new Map();
|
11
15
|
function loadRemoteNxPlugin(plugin, root) {
|
12
16
|
// this should only really be true when running unit tests within
|
13
17
|
// the Nx repo. We still need to start the worker in this case,
|
@@ -32,11 +36,11 @@ function loadRemoteNxPlugin(plugin, root) {
|
|
32
36
|
],
|
33
37
|
});
|
34
38
|
worker.send((0, messaging_1.createMessage)({ type: 'load', payload: { plugin, root } }));
|
35
|
-
pool.
|
36
|
-
|
39
|
+
pool.add(worker);
|
40
|
+
// logger.verbose(`[plugin-worker] started worker: ${worker.pid}`);
|
37
41
|
return new Promise((res, rej) => {
|
38
42
|
worker.on('message', createWorkerHandler(worker, res, rej));
|
39
|
-
worker.on('exit', (
|
43
|
+
worker.on('exit', createWorkerExitHandler(worker));
|
40
44
|
});
|
41
45
|
}
|
42
46
|
exports.loadRemoteNxPlugin = loadRemoteNxPlugin;
|
@@ -46,22 +50,19 @@ async function shutdownPluginWorkers() {
|
|
46
50
|
internal_api_1.nxPluginCache.clear();
|
47
51
|
// Marks the workers as shutdown so that we don't report unexpected exits
|
48
52
|
pluginWorkersShutdown = true;
|
49
|
-
|
53
|
+
// logger.verbose(`[plugin-pool] starting worker shutdown`);
|
54
|
+
const pending = getPendingPromises(pool, pidMap);
|
55
|
+
if (pending.length > 0) {
|
56
|
+
// logger.verbose(
|
57
|
+
// `[plugin-pool] waiting for ${pending.length} pending operations to complete`
|
58
|
+
// );
|
59
|
+
await Promise.all(pending);
|
60
|
+
}
|
61
|
+
// logger.verbose(`[plugin-pool] all pending operations completed`);
|
50
62
|
for (const p of pool) {
|
51
|
-
p.
|
52
|
-
if (error) {
|
53
|
-
// This occurs when the worker is already dead, and we can ignore it
|
54
|
-
}
|
55
|
-
else {
|
56
|
-
promises.push(
|
57
|
-
// Create a promise that resolves when the worker exits
|
58
|
-
new Promise((res, rej) => {
|
59
|
-
p.once('exit', () => res());
|
60
|
-
}));
|
61
|
-
}
|
62
|
-
});
|
63
|
+
p.kill('SIGINT');
|
63
64
|
}
|
64
|
-
|
65
|
+
// logger.verbose(`[plugin-pool] all workers killed`);
|
65
66
|
}
|
66
67
|
exports.shutdownPluginWorkers = shutdownPluginWorkers;
|
67
68
|
/**
|
@@ -72,67 +73,56 @@ exports.shutdownPluginWorkers = shutdownPluginWorkers;
|
|
72
73
|
* @returns Function to handle messages from the worker
|
73
74
|
*/
|
74
75
|
function createWorkerHandler(worker, onload, onloadError) {
|
75
|
-
// We store resolver and rejecter functions in the outer scope so that we can
|
76
|
-
// resolve/reject the promise from the message handler. The flow is something like:
|
77
|
-
// 1. plugin api called
|
78
|
-
// 2. remote plugin sends message to worker, creates promise and stores resolver/rejecter
|
79
|
-
// 3. worker performs API request
|
80
|
-
// 4. worker sends result back to main process
|
81
|
-
// 5. main process resolves/rejects promise based on result
|
82
|
-
let createNodesResolver;
|
83
|
-
let createNodesRejecter;
|
84
|
-
let createDependenciesResolver;
|
85
|
-
let createDependenciesRejecter;
|
86
|
-
let processProjectGraphResolver;
|
87
|
-
let processProjectGraphRejecter;
|
88
76
|
let pluginName;
|
89
77
|
return function (message) {
|
90
78
|
const parsed = JSON.parse(message);
|
91
|
-
|
79
|
+
// logger.verbose(
|
80
|
+
// `[plugin-pool] received message: ${parsed.type} from ${
|
81
|
+
// pluginName ?? worker.pid
|
82
|
+
// }`
|
83
|
+
// );
|
92
84
|
(0, messaging_1.consumeMessage)(parsed, {
|
93
85
|
'load-result': (result) => {
|
94
86
|
if (result.success) {
|
95
87
|
const { name, createNodesPattern } = result;
|
96
88
|
pluginName = name;
|
97
|
-
|
89
|
+
const pending = new Set();
|
90
|
+
pidMap.set(worker.pid, { name, pending });
|
98
91
|
onload({
|
99
92
|
name,
|
100
93
|
createNodes: createNodesPattern
|
101
94
|
? [
|
102
95
|
createNodesPattern,
|
103
96
|
(configFiles, ctx) => {
|
104
|
-
|
97
|
+
const tx = pluginName + ':createNodes:' + performance.now();
|
98
|
+
return registerPendingPromise(tx, pending, () => {
|
105
99
|
worker.send((0, messaging_1.createMessage)({
|
106
100
|
type: 'createNodes',
|
107
|
-
payload: { configFiles, context: ctx },
|
101
|
+
payload: { configFiles, context: ctx, tx },
|
108
102
|
}));
|
109
|
-
createNodesResolver = res;
|
110
|
-
createNodesRejecter = rej;
|
111
103
|
});
|
112
104
|
},
|
113
105
|
]
|
114
106
|
: undefined,
|
115
107
|
createDependencies: result.hasCreateDependencies
|
116
108
|
? (opts, ctx) => {
|
117
|
-
|
109
|
+
const tx = pluginName + ':createDependencies:' + performance.now();
|
110
|
+
return registerPendingPromise(tx, pending, () => {
|
118
111
|
worker.send((0, messaging_1.createMessage)({
|
119
112
|
type: 'createDependencies',
|
120
|
-
payload: { context: ctx },
|
113
|
+
payload: { context: ctx, tx },
|
121
114
|
}));
|
122
|
-
createDependenciesResolver = res;
|
123
|
-
createDependenciesRejecter = rej;
|
124
115
|
});
|
125
116
|
}
|
126
117
|
: undefined,
|
127
118
|
processProjectGraph: result.hasProcessProjectGraph
|
128
119
|
? (graph, ctx) => {
|
129
|
-
|
120
|
+
const tx = pluginName + ':processProjectGraph:' + performance.now();
|
121
|
+
return registerPendingPromise(tx, pending, () => {
|
130
122
|
worker.send((0, messaging_1.createMessage)({
|
131
123
|
type: 'processProjectGraph',
|
132
|
-
payload: { graph, ctx },
|
124
|
+
payload: { graph, ctx, tx },
|
133
125
|
}));
|
134
|
-
processProjectGraphResolver = res;
|
135
|
-
processProjectGraphRejecter = rej;
|
136
126
|
});
|
137
127
|
}
|
138
128
|
: undefined,
|
@@ -142,47 +132,85 @@ function createWorkerHandler(worker, onload, onloadError) {
|
|
142
132
|
onloadError(result.error);
|
143
133
|
}
|
144
134
|
},
|
145
|
-
createDependenciesResult: (result) => {
|
135
|
+
createDependenciesResult: ({ tx, ...result }) => {
|
136
|
+
const { resolver, rejecter } = promiseBank.get(tx);
|
146
137
|
if (result.success) {
|
147
|
-
|
148
|
-
createDependenciesResolver = undefined;
|
138
|
+
resolver(result.dependencies);
|
149
139
|
}
|
150
140
|
else if (result.success === false) {
|
151
|
-
|
152
|
-
createDependenciesRejecter = undefined;
|
141
|
+
rejecter(result.error);
|
153
142
|
}
|
143
|
+
pidMap.get(worker.pid)?.pending.delete(tx);
|
144
|
+
promiseBank.delete(tx);
|
154
145
|
},
|
155
|
-
createNodesResult: (
|
156
|
-
|
157
|
-
|
158
|
-
|
146
|
+
createNodesResult: ({ tx, ...result }) => {
|
147
|
+
const { resolver, rejecter } = promiseBank.get(tx);
|
148
|
+
if (result.success) {
|
149
|
+
resolver(result.result);
|
159
150
|
}
|
160
|
-
else if (
|
161
|
-
|
162
|
-
createNodesRejecter = undefined;
|
151
|
+
else if (result.success === false) {
|
152
|
+
rejecter(result.error);
|
163
153
|
}
|
154
|
+
pidMap.get(worker.pid)?.pending.delete(tx);
|
155
|
+
promiseBank.delete(tx);
|
164
156
|
},
|
165
|
-
processProjectGraphResult: (result) => {
|
157
|
+
processProjectGraphResult: ({ tx, ...result }) => {
|
158
|
+
const { resolver, rejecter } = promiseBank.get(tx);
|
166
159
|
if (result.success) {
|
167
|
-
|
168
|
-
processProjectGraphResolver = undefined;
|
160
|
+
resolver(result.graph);
|
169
161
|
}
|
170
162
|
else if (result.success === false) {
|
171
|
-
|
172
|
-
processProjectGraphRejecter = undefined;
|
163
|
+
rejecter(result.error);
|
173
164
|
}
|
165
|
+
pidMap.get(worker.pid)?.pending.delete(tx);
|
166
|
+
promiseBank.delete(tx);
|
174
167
|
},
|
175
168
|
});
|
176
169
|
};
|
177
170
|
}
|
178
|
-
function
|
171
|
+
function createWorkerExitHandler(worker) {
|
179
172
|
return () => {
|
180
173
|
if (!pluginWorkersShutdown) {
|
174
|
+
pidMap.get(worker.pid)?.pending.forEach((tx) => {
|
175
|
+
const { rejecter } = promiseBank.get(tx);
|
176
|
+
rejecter(new Error(`Plugin worker ${pidMap.get(worker.pid).name ?? worker.pid} exited unexpectedly with code ${worker.exitCode}`));
|
177
|
+
});
|
181
178
|
shutdownPluginWorkers();
|
182
|
-
throw new Error(`[Nx] plugin worker ${pidMap.get(worker.pid) ?? worker.pid} exited unexpectedly`);
|
183
179
|
}
|
184
180
|
};
|
185
181
|
}
|
186
182
|
process.on('exit', () => {
|
187
|
-
|
183
|
+
if (pool.size) {
|
184
|
+
shutdownPluginWorkers();
|
185
|
+
}
|
188
186
|
});
|
187
|
+
function getPendingPromises(pool, pidMap) {
|
188
|
+
const pendingTxs = [];
|
189
|
+
for (const p of pool) {
|
190
|
+
const { pending } = pidMap.get(p.pid) ?? { pending: new Set() };
|
191
|
+
for (const tx of pending) {
|
192
|
+
pendingTxs.push(promiseBank.get(tx)?.promise);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
return pendingTxs;
|
196
|
+
}
|
197
|
+
function registerPendingPromise(tx, pending, callback) {
|
198
|
+
let resolver, rejecter;
|
199
|
+
const promise = new Promise((res, rej) => {
|
200
|
+
resolver = res;
|
201
|
+
rejecter = rej;
|
202
|
+
callback();
|
203
|
+
}).then((val) => {
|
204
|
+
// Remove the promise from the pending set
|
205
|
+
pending.delete(tx);
|
206
|
+
// Return the original value
|
207
|
+
return val;
|
208
|
+
});
|
209
|
+
pending.add(tx);
|
210
|
+
promiseBank.set(tx, {
|
211
|
+
promise,
|
212
|
+
resolver,
|
213
|
+
rejecter,
|
214
|
+
});
|
215
|
+
return promise;
|
216
|
+
}
|
@@ -4,6 +4,7 @@ const installation_directory_1 = require("../../utils/installation-directory");
|
|
4
4
|
const worker_api_1 = require("./worker-api");
|
5
5
|
const messaging_1 = require("./messaging");
|
6
6
|
const retrieve_workspace_files_1 = require("../utils/retrieve-workspace-files");
|
7
|
+
const utils_1 = require("./utils");
|
7
8
|
global.NX_GRAPH_CREATION = true;
|
8
9
|
let plugin;
|
9
10
|
let pluginOptions;
|
@@ -34,51 +35,48 @@ process.on('message', async (message) => {
|
|
34
35
|
};
|
35
36
|
}
|
36
37
|
},
|
37
|
-
|
38
|
-
process.exit(0);
|
39
|
-
},
|
40
|
-
createNodes: async ({ configFiles, context }) => {
|
38
|
+
createNodes: async ({ configFiles, context, tx }) => {
|
41
39
|
try {
|
42
40
|
const result = await runCreateNodesInParallel(configFiles, context);
|
43
41
|
return {
|
44
42
|
type: 'createNodesResult',
|
45
|
-
payload: { result, success: true },
|
43
|
+
payload: { result, success: true, tx },
|
46
44
|
};
|
47
45
|
}
|
48
46
|
catch (e) {
|
49
47
|
return {
|
50
48
|
type: 'createNodesResult',
|
51
|
-
payload: { success: false, error: e.stack },
|
49
|
+
payload: { success: false, error: e.stack, tx },
|
52
50
|
};
|
53
51
|
}
|
54
52
|
},
|
55
|
-
createDependencies: async (
|
53
|
+
createDependencies: async ({ context, tx }) => {
|
56
54
|
try {
|
57
|
-
const result = await plugin.createDependencies(pluginOptions,
|
55
|
+
const result = await plugin.createDependencies(pluginOptions, context);
|
58
56
|
return {
|
59
57
|
type: 'createDependenciesResult',
|
60
|
-
payload: { dependencies: result, success: true },
|
58
|
+
payload: { dependencies: result, success: true, tx },
|
61
59
|
};
|
62
60
|
}
|
63
61
|
catch (e) {
|
64
62
|
return {
|
65
63
|
type: 'createDependenciesResult',
|
66
|
-
payload: { success: false, error: e.stack },
|
64
|
+
payload: { success: false, error: e.stack, tx },
|
67
65
|
};
|
68
66
|
}
|
69
67
|
},
|
70
|
-
processProjectGraph: async ({ graph, ctx }) => {
|
68
|
+
processProjectGraph: async ({ graph, ctx, tx }) => {
|
71
69
|
try {
|
72
70
|
const result = await plugin.processProjectGraph(graph, ctx);
|
73
71
|
return {
|
74
72
|
type: 'processProjectGraphResult',
|
75
|
-
payload: { graph: result, success: true },
|
73
|
+
payload: { graph: result, success: true, tx },
|
76
74
|
};
|
77
75
|
}
|
78
76
|
catch (e) {
|
79
77
|
return {
|
80
78
|
type: 'processProjectGraphResult',
|
81
|
-
payload: { success: false, error: e.stack },
|
79
|
+
payload: { success: false, error: e.stack, tx },
|
82
80
|
};
|
83
81
|
}
|
84
82
|
},
|
@@ -99,24 +97,19 @@ async function loadPluginFromWorker(plugin, root) {
|
|
99
97
|
function runCreateNodesInParallel(configFiles, context) {
|
100
98
|
const promises = configFiles.map((file) => {
|
101
99
|
performance.mark(`${plugin.name}:createNodes:${file} - start`);
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
})
|
109
|
-
|
110
|
-
|
111
|
-
performance.measure(`${plugin.name}:createNodes:${file}`, `${plugin.name}:createNodes:${file} - start`, `${plugin.name}:createNodes:${file} - end`);
|
112
|
-
return { ...r, pluginName: plugin.name, file };
|
113
|
-
});
|
114
|
-
}
|
115
|
-
else {
|
100
|
+
// Result is either static or a promise, using Promise.resolve lets us
|
101
|
+
// handle both cases with same logic
|
102
|
+
const value = Promise.resolve(plugin.createNodes[1](file, pluginOptions, context));
|
103
|
+
return value
|
104
|
+
.catch((e) => {
|
105
|
+
performance.mark(`${plugin.name}:createNodes:${file} - end`);
|
106
|
+
throw new utils_1.CreateNodesError(`Unable to create nodes for ${file} using plugin ${plugin.name}.`, e);
|
107
|
+
})
|
108
|
+
.then((r) => {
|
116
109
|
performance.mark(`${plugin.name}:createNodes:${file} - end`);
|
117
110
|
performance.measure(`${plugin.name}:createNodes:${file}`, `${plugin.name}:createNodes:${file} - start`, `${plugin.name}:createNodes:${file} - end`);
|
118
|
-
return { ...
|
119
|
-
}
|
111
|
+
return { ...r, pluginName: plugin.name, file };
|
112
|
+
});
|
120
113
|
});
|
121
114
|
return Promise.all(promises);
|
122
115
|
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import type { NxPluginV1 } from '../../utils/nx-plugin.deprecated';
|
2
|
+
import type { NormalizedPlugin, RemotePlugin } from './internal-api';
|
3
|
+
import type { NxPlugin, NxPluginV2 } from './public-api';
|
4
|
+
export declare function isNxPluginV2(plugin: NxPlugin): plugin is NxPluginV2;
|
5
|
+
export declare function isNxPluginV1(plugin: NxPlugin | RemotePlugin): plugin is NxPluginV1;
|
6
|
+
export declare function normalizeNxPlugin(plugin: NxPlugin): NormalizedPlugin;
|
7
|
+
export declare class CreateNodesError extends Error {
|
8
|
+
constructor(msg: any, cause: Error | unknown);
|
9
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.CreateNodesError = exports.normalizeNxPlugin = exports.isNxPluginV1 = exports.isNxPluginV2 = void 0;
|
4
|
+
const node_path_1 = require("node:path");
|
5
|
+
const workspaces_1 = require("../../config/workspaces");
|
6
|
+
const globs_1 = require("../../utils/globs");
|
7
|
+
function isNxPluginV2(plugin) {
|
8
|
+
return 'createNodes' in plugin || 'createDependencies' in plugin;
|
9
|
+
}
|
10
|
+
exports.isNxPluginV2 = isNxPluginV2;
|
11
|
+
function isNxPluginV1(plugin) {
|
12
|
+
return 'processProjectGraph' in plugin || 'projectFilePatterns' in plugin;
|
13
|
+
}
|
14
|
+
exports.isNxPluginV1 = isNxPluginV1;
|
15
|
+
function normalizeNxPlugin(plugin) {
|
16
|
+
if (isNxPluginV2(plugin)) {
|
17
|
+
return plugin;
|
18
|
+
}
|
19
|
+
if (isNxPluginV1(plugin) && plugin.projectFilePatterns) {
|
20
|
+
return {
|
21
|
+
...plugin,
|
22
|
+
createNodes: [
|
23
|
+
`*/**/${(0, globs_1.combineGlobPatterns)(plugin.projectFilePatterns)}`,
|
24
|
+
(configFilePath) => {
|
25
|
+
const root = (0, node_path_1.dirname)(configFilePath);
|
26
|
+
return {
|
27
|
+
projects: {
|
28
|
+
[root]: {
|
29
|
+
name: (0, workspaces_1.toProjectName)(configFilePath),
|
30
|
+
targets: plugin.registerProjectTargets?.(configFilePath),
|
31
|
+
},
|
32
|
+
},
|
33
|
+
};
|
34
|
+
},
|
35
|
+
],
|
36
|
+
};
|
37
|
+
}
|
38
|
+
return plugin;
|
39
|
+
}
|
40
|
+
exports.normalizeNxPlugin = normalizeNxPlugin;
|
41
|
+
class CreateNodesError extends Error {
|
42
|
+
constructor(msg, cause) {
|
43
|
+
const message = `${msg} ${!cause
|
44
|
+
? ''
|
45
|
+
: cause instanceof Error
|
46
|
+
? `\n\n\t Inner Error: ${cause.stack}`
|
47
|
+
: cause}`;
|
48
|
+
// These errors are thrown during a JS callback which is invoked via rust.
|
49
|
+
// The errors messaging gets lost in the rust -> js -> rust transition, but
|
50
|
+
// logging the error here will ensure that it is visible in the console.
|
51
|
+
console.error(message);
|
52
|
+
super(message, { cause });
|
53
|
+
}
|
54
|
+
}
|
55
|
+
exports.CreateNodesError = CreateNodesError;
|
@@ -15,14 +15,14 @@ const find_project_for_path_1 = require("../utils/find-project-for-path");
|
|
15
15
|
const path_1 = require("../../utils/path");
|
16
16
|
const logger_1 = require("../../utils/logger");
|
17
17
|
const node_path_1 = require("node:path");
|
18
|
-
const
|
18
|
+
const utils_1 = require("./utils");
|
19
19
|
async function loadNxPluginAsync(pluginConfiguration, paths, projects, root) {
|
20
20
|
const { plugin: moduleName, options } = typeof pluginConfiguration === 'object'
|
21
21
|
? pluginConfiguration
|
22
22
|
: { plugin: pluginConfiguration, options: undefined };
|
23
23
|
performance.mark(`Load Nx Plugin: ${moduleName} - start`);
|
24
24
|
let { pluginPath, name } = await getPluginPathAndName(moduleName, paths, projects, root);
|
25
|
-
const plugin = (0,
|
25
|
+
const plugin = (0, utils_1.normalizeNxPlugin)(await importPluginModule(pluginPath));
|
26
26
|
plugin.name ??= name;
|
27
27
|
performance.mark(`Load Nx Plugin: ${moduleName} - end`);
|
28
28
|
performance.measure(`Load Nx Plugin: ${moduleName}`, `Load Nx Plugin: ${moduleName} - start`, `Load Nx Plugin: ${moduleName} - end`);
|
@@ -65,6 +65,7 @@ function readProjectsConfigurationFromProjectGraph(projectGraph) {
|
|
65
65
|
}
|
66
66
|
exports.readProjectsConfigurationFromProjectGraph = readProjectsConfigurationFromProjectGraph;
|
67
67
|
async function buildProjectGraphAndSourceMapsWithoutDaemon() {
|
68
|
+
global.NX_GRAPH_CREATION = true;
|
68
69
|
const nxJson = (0, nx_json_1.readNxJson)();
|
69
70
|
perf_hooks_1.performance.mark('retrieve-project-configurations:start');
|
70
71
|
const { projects, externalNodes, sourceMaps, projectRootMap } = await (0, retrieve_workspace_files_1.retrieveProjectConfigurations)(workspace_root_1.workspaceRoot, nxJson);
|
@@ -76,6 +77,7 @@ async function buildProjectGraphAndSourceMapsWithoutDaemon() {
|
|
76
77
|
perf_hooks_1.performance.mark('build-project-graph-using-project-file-map:start');
|
77
78
|
const projectGraph = (await (0, build_project_graph_1.buildProjectGraphUsingProjectFileMap)(projects, externalNodes, fileMap, allWorkspaceFiles, rustReferences, cacheEnabled ? (0, nx_deps_cache_1.readFileMapCache)() : null, cacheEnabled)).projectGraph;
|
78
79
|
perf_hooks_1.performance.mark('build-project-graph-using-project-file-map:end');
|
80
|
+
delete global.NX_GRAPH_CREATION;
|
79
81
|
return { projectGraph, sourceMaps };
|
80
82
|
}
|
81
83
|
exports.buildProjectGraphAndSourceMapsWithoutDaemon = buildProjectGraphAndSourceMapsWithoutDaemon;
|
@@ -7,6 +7,8 @@ const workspace_root_1 = require("../../utils/workspace-root");
|
|
7
7
|
const target_defaults_plugin_1 = require("../../plugins/target-defaults/target-defaults-plugin");
|
8
8
|
const minimatch_1 = require("minimatch");
|
9
9
|
const path_1 = require("path");
|
10
|
+
const utils_1 = require("../plugins/utils");
|
11
|
+
const plugin_pool_1 = require("../plugins/plugin-pool");
|
10
12
|
function mergeProjectConfigurationIntoRootMap(projectRootMap, project, configurationSourceMaps, sourceInformation,
|
11
13
|
// This function is used when reading project configuration
|
12
14
|
// in generators, where we don't want to do this.
|
@@ -139,23 +141,18 @@ plugins, root = workspace_root_1.workspaceRoot) {
|
|
139
141
|
}
|
140
142
|
const matchedFiles = [];
|
141
143
|
performance.mark(`${plugin.name}:createNodes - start`);
|
142
|
-
// Set this globally to allow plugins to know if they are being called from the project graph creation
|
143
|
-
global.NX_GRAPH_CREATION = true;
|
144
144
|
for (const file of projectFiles) {
|
145
145
|
if ((0, minimatch_1.minimatch)(file, pattern, { dot: true })) {
|
146
146
|
matchedFiles.push(file);
|
147
147
|
}
|
148
148
|
}
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
catch (e) {
|
157
|
-
throw new CreateNodesError(`Unable to create nodes using plugin ${plugin.name}.`, e);
|
158
|
-
}
|
149
|
+
let r = createNodes(matchedFiles, {
|
150
|
+
nxJsonConfiguration: nxJson,
|
151
|
+
workspaceRoot: root,
|
152
|
+
}).catch((e) => (0, plugin_pool_1.shutdownPluginWorkers)().then(() => {
|
153
|
+
throw e;
|
154
|
+
}));
|
155
|
+
results.push(r);
|
159
156
|
}
|
160
157
|
return Promise.all(results).then((results) => {
|
161
158
|
performance.mark('createNodes:merge - start');
|
@@ -173,7 +170,7 @@ plugins, root = workspace_root_1.workspaceRoot) {
|
|
173
170
|
mergeProjectConfigurationIntoRootMap(projectRootMap, project, configurationSourceMaps, [file, pluginName]);
|
174
171
|
}
|
175
172
|
catch (e) {
|
176
|
-
throw new CreateNodesError(`Unable to merge project information for "${project.root}" from ${result.file} using plugin ${result.pluginName}.`, e);
|
173
|
+
throw new utils_1.CreateNodesError(`Unable to merge project information for "${project.root}" from ${result.file} using plugin ${result.pluginName}.`, e);
|
177
174
|
}
|
178
175
|
}
|
179
176
|
Object.assign(externalNodes, pluginExternalNodes);
|
@@ -229,20 +226,6 @@ function readProjectConfigurationsFromRootMap(projectRootMap) {
|
|
229
226
|
return projects;
|
230
227
|
}
|
231
228
|
exports.readProjectConfigurationsFromRootMap = readProjectConfigurationsFromRootMap;
|
232
|
-
class CreateNodesError extends Error {
|
233
|
-
constructor(msg, cause) {
|
234
|
-
const message = `${msg} ${!cause
|
235
|
-
? ''
|
236
|
-
: cause instanceof Error
|
237
|
-
? `\n\n\t Inner Error: ${cause.stack}`
|
238
|
-
: cause}`;
|
239
|
-
// These errors are thrown during a JS callback which is invoked via rust.
|
240
|
-
// The errors messaging gets lost in the rust -> js -> rust transition, but
|
241
|
-
// logging the error here will ensure that it is visible in the console.
|
242
|
-
console.error(message);
|
243
|
-
super(message, { cause });
|
244
|
-
}
|
245
|
-
}
|
246
229
|
/**
|
247
230
|
* Merges two targets.
|
248
231
|
*
|
@@ -9,6 +9,7 @@ const internal_api_1 = require("../plugins/internal-api");
|
|
9
9
|
const workspace_context_1 = require("../../utils/workspace-context");
|
10
10
|
const build_all_workspace_files_1 = require("./build-all-workspace-files");
|
11
11
|
const path_1 = require("path");
|
12
|
+
const plugin_pool_1 = require("../plugins/plugin-pool");
|
12
13
|
/**
|
13
14
|
* Walks the workspace directory to create the `projectFileMap`, `ProjectConfigurations` and `allWorkspaceFiles`
|
14
15
|
* @throws
|
@@ -41,7 +42,11 @@ exports.retrieveWorkspaceFiles = retrieveWorkspaceFiles;
|
|
41
42
|
*/
|
42
43
|
async function retrieveProjectConfigurations(workspaceRoot, nxJson) {
|
43
44
|
const plugins = await (0, internal_api_1.loadNxPlugins)(nxJson?.plugins ?? [], workspaceRoot);
|
44
|
-
|
45
|
+
const projects = await _retrieveProjectConfigurations(workspaceRoot, nxJson, plugins);
|
46
|
+
if (!global.NX_GRAPH_CREATION) {
|
47
|
+
await (0, plugin_pool_1.shutdownPluginWorkers)();
|
48
|
+
}
|
49
|
+
return projects;
|
45
50
|
}
|
46
51
|
exports.retrieveProjectConfigurations = retrieveProjectConfigurations;
|
47
52
|
async function retrieveProjectConfigurationsWithAngularProjects(workspaceRoot, nxJson) {
|