nx 18.1.0-canary.20240223-21e7648 → 18.1.0-canary.20240224-26b266f
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/adapter/angular-json.d.ts +2 -1
- package/src/adapter/angular-json.js +1 -0
- package/src/adapter/ngcli-adapter.js +3 -3
- package/src/command-line/generate/generator-utils.js +2 -2
- package/src/command-line/init/init-v2.js +17 -11
- package/src/command-line/migrate/migrate.js +3 -1
- package/src/command-line/run/executor-utils.js +2 -2
- package/src/config/schema-utils.js +2 -2
- package/src/devkit-exports.d.ts +2 -1
- package/src/devkit-internals.d.ts +1 -0
- package/src/devkit-internals.js +3 -1
- package/src/generators/utils/project-configuration.js +2 -2
- package/src/migrations/update-15-1-0/set-project-names.js +2 -2
- package/src/plugins/js/index.d.ts +1 -1
- package/src/plugins/js/lock-file/lock-file.d.ts +1 -1
- package/src/plugins/js/lock-file/npm-parser.d.ts +1 -1
- package/src/plugins/js/lock-file/pnpm-parser.d.ts +1 -1
- package/src/plugins/js/lock-file/yarn-parser.d.ts +1 -1
- package/src/plugins/js/project-graph/build-dependencies/build-dependencies.d.ts +1 -1
- package/src/plugins/js/project-graph/build-dependencies/explicit-package-json-dependencies.d.ts +1 -1
- package/src/plugins/js/project-graph/build-dependencies/explicit-project-dependencies.d.ts +1 -1
- package/src/plugins/package-json-workspaces/create-nodes.d.ts +2 -2
- package/src/plugins/package-json-workspaces/create-nodes.js +24 -31
- package/src/plugins/package-json-workspaces/index.d.ts +1 -0
- package/src/plugins/package-json-workspaces/index.js +2 -0
- package/src/plugins/project-json/build-nodes/package-json-next-to-project-json.d.ts +2 -1
- package/src/plugins/project-json/build-nodes/package-json-next-to-project-json.js +1 -0
- package/src/plugins/project-json/build-nodes/project-json.d.ts +2 -1
- package/src/plugins/project-json/build-nodes/project-json.js +1 -0
- package/src/plugins/target-defaults/target-defaults-plugin.d.ts +4 -4
- package/src/plugins/target-defaults/target-defaults-plugin.js +24 -27
- package/src/project-graph/affected/locators/project-glob-changes.js +2 -3
- package/src/project-graph/build-project-graph.js +10 -8
- package/src/project-graph/file-utils.js +3 -3
- package/src/project-graph/plugins/index.d.ts +2 -0
- package/src/project-graph/plugins/index.js +8 -0
- package/src/project-graph/plugins/internal-api.d.ts +21 -0
- package/src/project-graph/plugins/internal-api.js +84 -0
- package/src/project-graph/plugins/messaging.d.ts +89 -0
- package/src/project-graph/plugins/messaging.js +23 -0
- package/src/project-graph/plugins/plugin-pool.d.ts +4 -0
- package/src/project-graph/plugins/plugin-pool.js +188 -0
- package/src/project-graph/plugins/plugin-worker.d.ts +1 -0
- package/src/project-graph/plugins/plugin-worker.js +122 -0
- package/src/{utils/nx-plugin.d.ts → project-graph/plugins/public-api.d.ts} +6 -40
- package/src/project-graph/plugins/public-api.js +4 -0
- package/src/project-graph/plugins/worker-api.d.ts +26 -0
- package/src/project-graph/plugins/worker-api.js +177 -0
- package/src/project-graph/project-graph-builder.d.ts +1 -1
- package/src/project-graph/project-graph.js +0 -2
- package/src/project-graph/utils/normalize-project-nodes.d.ts +1 -1
- package/src/project-graph/utils/project-configuration-utils.d.ts +2 -2
- package/src/project-graph/utils/project-configuration-utils.js +27 -47
- package/src/project-graph/utils/retrieve-workspace-files.d.ts +8 -4
- package/src/project-graph/utils/retrieve-workspace-files.js +11 -14
- package/src/utils/logger.d.ts +1 -0
- package/src/utils/logger.js +5 -0
- package/src/utils/nx-plugin.deprecated.d.ts +4 -2
- package/src/utils/nx-plugin.deprecated.js +4 -4
- package/src/utils/package-json.js +2 -2
- package/src/utils/plugins/plugin-capabilities.d.ts +1 -1
- package/src/utils/plugins/plugin-capabilities.js +8 -7
- package/src/utils/nx-plugin.js +0 -293
@@ -8,14 +8,14 @@ const assert_workspace_validity_1 = require("../utils/assert-workspace-validity"
|
|
8
8
|
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
|
-
const
|
11
|
+
const internal_api_1 = require("./plugins/internal-api");
|
12
12
|
const typescript_1 = require("../plugins/js/utils/typescript");
|
13
13
|
const fileutils_1 = require("../utils/fileutils");
|
14
14
|
const project_graph_builder_1 = require("./project-graph-builder");
|
15
15
|
const configuration_1 = require("../config/configuration");
|
16
16
|
const fs_1 = require("fs");
|
17
|
-
const installation_directory_1 = require("../utils/installation-directory");
|
18
17
|
const output_1 = require("../utils/output");
|
18
|
+
const plugin_pool_1 = require("./plugins/plugin-pool");
|
19
19
|
let storedFileMap = null;
|
20
20
|
let storedAllWorkspaceFiles = null;
|
21
21
|
let storedRustReferences = null;
|
@@ -70,6 +70,7 @@ async function buildProjectGraphUsingProjectFileMap(projects, externalNodes, fil
|
|
70
70
|
if (shouldWriteCache) {
|
71
71
|
(0, nx_deps_cache_1.writeCache)(projectFileMapCache, projectGraph);
|
72
72
|
}
|
73
|
+
await (0, plugin_pool_1.shutdownPluginWorkers)();
|
73
74
|
return {
|
74
75
|
projectGraph,
|
75
76
|
projectFileMapCache,
|
@@ -140,11 +141,11 @@ function createContext(projects, nxJson, externalNodes, fileMap, filesToProcess)
|
|
140
141
|
};
|
141
142
|
}
|
142
143
|
async function updateProjectGraphWithPlugins(context, initProjectGraph) {
|
143
|
-
const plugins = await (0,
|
144
|
+
const plugins = await (0, internal_api_1.loadNxPlugins)(context.nxJsonConfiguration?.plugins, context.workspaceRoot);
|
144
145
|
let graph = initProjectGraph;
|
145
|
-
for (const
|
146
|
+
for (const plugin of plugins) {
|
146
147
|
try {
|
147
|
-
if ((0,
|
148
|
+
if ((0, internal_api_1.isNxPluginV1)(plugin) &&
|
148
149
|
plugin.processProjectGraph &&
|
149
150
|
!plugin.createDependencies) {
|
150
151
|
output_1.output.warn({
|
@@ -182,13 +183,14 @@ async function updateProjectGraphWithPlugins(context, initProjectGraph) {
|
|
182
183
|
}
|
183
184
|
}
|
184
185
|
const builder = new project_graph_builder_1.ProjectGraphBuilder(graph, context.fileMap.projectFileMap, context.fileMap.nonProjectFiles);
|
185
|
-
const createDependencyPlugins = plugins.filter((
|
186
|
-
await Promise.all(createDependencyPlugins.map(async (
|
186
|
+
const createDependencyPlugins = plugins.filter((plugin) => (0, internal_api_1.isNxPluginV2)(plugin) && plugin.createDependencies);
|
187
|
+
await Promise.all(createDependencyPlugins.map(async (plugin) => {
|
187
188
|
perf_hooks_1.performance.mark(`${plugin.name}:createDependencies - start`);
|
188
189
|
// Set this globally to allow plugins to know if they are being called from the project graph creation
|
189
190
|
global.NX_GRAPH_CREATION = true;
|
190
191
|
try {
|
191
|
-
|
192
|
+
// TODO: we shouldn't have to pass null here
|
193
|
+
const dependencies = await plugin.createDependencies(null, {
|
192
194
|
...context,
|
193
195
|
});
|
194
196
|
for (const dep of dependencies) {
|
@@ -147,21 +147,21 @@ Object.defineProperty(exports, "workspaceLayout", { enumerable: true, get: funct
|
|
147
147
|
* TODO(v19): Remove this function.
|
148
148
|
*/
|
149
149
|
function getProjectsSyncNoInference(root, nxJson) {
|
150
|
-
const projectFiles = (0, retrieve_workspace_files_1.retrieveProjectConfigurationPaths)(root, (0, nx_plugin_deprecated_1.getDefaultPluginsSync)(root));
|
150
|
+
const projectFiles = (0, retrieve_workspace_files_1.retrieveProjectConfigurationPaths)(root, (0, nx_plugin_deprecated_1.getDefaultPluginsSync)(root).map((p) => p.plugin));
|
151
151
|
const plugins = [
|
152
152
|
{ plugin: package_json_next_to_project_json_1.PackageJsonProjectsNextToProjectJsonPlugin },
|
153
153
|
...(0, nx_plugin_deprecated_1.getDefaultPluginsSync)(root),
|
154
154
|
];
|
155
155
|
const projectRootMap = new Map();
|
156
156
|
// We iterate over plugins first - this ensures that plugins specified first take precedence.
|
157
|
-
for (const { plugin
|
157
|
+
for (const { plugin } of plugins) {
|
158
158
|
const [pattern, createNodes] = plugin.createNodes ?? [];
|
159
159
|
if (!pattern) {
|
160
160
|
continue;
|
161
161
|
}
|
162
162
|
for (const file of projectFiles) {
|
163
163
|
if ((0, minimatch_1.minimatch)(file, pattern, { dot: true })) {
|
164
|
-
let r = createNodes(file,
|
164
|
+
let r = createNodes(file, {}, {
|
165
165
|
nxJsonConfiguration: nxJson,
|
166
166
|
workspaceRoot: root,
|
167
167
|
});
|
@@ -0,0 +1,8 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.registerPluginTSTranspiler = exports.readPluginPackageJson = void 0;
|
4
|
+
const tslib_1 = require("tslib");
|
5
|
+
tslib_1.__exportStar(require("./public-api"), exports);
|
6
|
+
var worker_api_1 = require("./worker-api");
|
7
|
+
Object.defineProperty(exports, "readPluginPackageJson", { enumerable: true, get: function () { return worker_api_1.readPluginPackageJson; } });
|
8
|
+
Object.defineProperty(exports, "registerPluginTSTranspiler", { enumerable: true, get: function () { return worker_api_1.registerPluginTSTranspiler; } });
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { PluginConfiguration } from '../../config/nx-json';
|
2
|
+
import { NxPluginV1 } from '../../utils/nx-plugin.deprecated';
|
3
|
+
import { CreateNodesContext, CreateNodesResult, NxPlugin, NxPluginV2 } from './public-api';
|
4
|
+
export type CreateNodesResultWithContext = CreateNodesResult & {
|
5
|
+
file: string;
|
6
|
+
pluginName: string;
|
7
|
+
};
|
8
|
+
export type NormalizedPlugin = NxPluginV2 & Pick<NxPluginV1, 'processProjectGraph'>;
|
9
|
+
export type RemotePlugin = Omit<NormalizedPlugin, 'createNodes'> & {
|
10
|
+
createNodes: [
|
11
|
+
filePattern: string,
|
12
|
+
fn: (matchedFiles: string[], context: CreateNodesContext) => Promise<CreateNodesResultWithContext[]>
|
13
|
+
];
|
14
|
+
};
|
15
|
+
export declare const nxPluginCache: Map<unknown, RemotePlugin>;
|
16
|
+
export declare function loadNxPlugins(plugins: PluginConfiguration[], root?: string): Promise<RemotePlugin[]>;
|
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
|
+
export declare function getDefaultPlugins(root: string): Promise<string[]>;
|
@@ -0,0 +1,84 @@
|
|
1
|
+
"use strict";
|
2
|
+
// This file contains the bits and bobs of the internal API for loading and interacting with Nx plugins.
|
3
|
+
// For the public API, used by plugin authors, see `./public-api.ts`.
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
5
|
+
exports.getDefaultPlugins = exports.normalizeNxPlugin = exports.isNxPluginV1 = exports.isNxPluginV2 = exports.loadNxPlugin = exports.loadNxPlugins = exports.nxPluginCache = void 0;
|
6
|
+
const path_1 = require("path");
|
7
|
+
const workspaces_1 = require("../../config/workspaces");
|
8
|
+
const globs_1 = require("../../utils/globs");
|
9
|
+
const workspace_root_1 = require("../../utils/workspace-root");
|
10
|
+
const angular_json_1 = require("../../adapter/angular-json");
|
11
|
+
const plugin_pool_1 = require("./plugin-pool");
|
12
|
+
// Short lived cache (cleared between cmd runs)
|
13
|
+
// holding resolved nx plugin objects.
|
14
|
+
// Allows loaded plugins to not be reloaded when
|
15
|
+
// referenced multiple times.
|
16
|
+
exports.nxPluginCache = new Map();
|
17
|
+
async function loadNxPlugins(plugins, root = workspace_root_1.workspaceRoot) {
|
18
|
+
const result = [];
|
19
|
+
plugins ??= [];
|
20
|
+
plugins.unshift((0, path_1.join)(__dirname, '../../plugins/project-json/build-nodes/package-json-next-to-project-json'));
|
21
|
+
// We push the nx core node plugins onto the end, s.t. it overwrites any other plugins
|
22
|
+
plugins.push(...(await getDefaultPlugins(root)));
|
23
|
+
for (const plugin of plugins) {
|
24
|
+
result.push(loadNxPlugin(plugin, root));
|
25
|
+
}
|
26
|
+
return Promise.all(result);
|
27
|
+
}
|
28
|
+
exports.loadNxPlugins = loadNxPlugins;
|
29
|
+
async function loadNxPlugin(plugin, root = workspace_root_1.workspaceRoot) {
|
30
|
+
const cacheKey = JSON.stringify(plugin);
|
31
|
+
if (exports.nxPluginCache.has(cacheKey)) {
|
32
|
+
return exports.nxPluginCache.get(cacheKey);
|
33
|
+
}
|
34
|
+
const loadedPlugin = await (0, plugin_pool_1.loadRemoteNxPlugin)(plugin, root);
|
35
|
+
exports.nxPluginCache.set(cacheKey, loadedPlugin);
|
36
|
+
return loadedPlugin;
|
37
|
+
}
|
38
|
+
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
|
+
async function getDefaultPlugins(root) {
|
74
|
+
return [
|
75
|
+
(0, path_1.join)(__dirname, '../../plugins/js'),
|
76
|
+
(0, path_1.join)(__dirname, '../../plugins/target-defaults/target-defaults-plugin'),
|
77
|
+
...((0, angular_json_1.shouldMergeAngularProjects)(root, false)
|
78
|
+
? [(0, path_1.join)(__dirname, '../../adapter/angular-json')]
|
79
|
+
: []),
|
80
|
+
(0, path_1.join)(__dirname, '../../plugins/package-json-workspaces'),
|
81
|
+
(0, path_1.join)(__dirname, '../../plugins/project-json/build-nodes/project-json'),
|
82
|
+
];
|
83
|
+
}
|
84
|
+
exports.getDefaultPlugins = getDefaultPlugins;
|
@@ -0,0 +1,89 @@
|
|
1
|
+
import { ProjectGraph, ProjectGraphProcessorContext } from '../../config/project-graph';
|
2
|
+
import { PluginConfiguration } from '../../config/nx-json';
|
3
|
+
import { CreateDependenciesContext, CreateNodesContext } from './public-api';
|
4
|
+
import { RemotePlugin } from './internal-api';
|
5
|
+
export interface PluginWorkerLoadMessage {
|
6
|
+
type: 'load';
|
7
|
+
payload: {
|
8
|
+
plugin: PluginConfiguration;
|
9
|
+
root: string;
|
10
|
+
};
|
11
|
+
}
|
12
|
+
export interface PluginWorkerLoadResult {
|
13
|
+
type: 'load-result';
|
14
|
+
payload: {
|
15
|
+
name: string;
|
16
|
+
createNodesPattern: string;
|
17
|
+
hasCreateDependencies: boolean;
|
18
|
+
hasProcessProjectGraph: boolean;
|
19
|
+
success: true;
|
20
|
+
} | {
|
21
|
+
success: false;
|
22
|
+
error: string;
|
23
|
+
};
|
24
|
+
}
|
25
|
+
export interface PluginWorkerShutdownMessage {
|
26
|
+
type: 'shutdown';
|
27
|
+
payload: undefined;
|
28
|
+
}
|
29
|
+
export interface PluginWorkerCreateNodesMessage {
|
30
|
+
type: 'createNodes';
|
31
|
+
payload: {
|
32
|
+
configFiles: string[];
|
33
|
+
context: CreateNodesContext;
|
34
|
+
};
|
35
|
+
}
|
36
|
+
export interface PluginWorkerCreateNodesResult {
|
37
|
+
type: 'createNodesResult';
|
38
|
+
payload: {
|
39
|
+
success: true;
|
40
|
+
result: Awaited<ReturnType<RemotePlugin['createNodes'][1]>>;
|
41
|
+
} | {
|
42
|
+
success: false;
|
43
|
+
error: string;
|
44
|
+
};
|
45
|
+
}
|
46
|
+
export interface PluginCreateDependenciesMessage {
|
47
|
+
type: 'createDependencies';
|
48
|
+
payload: {
|
49
|
+
context: CreateDependenciesContext;
|
50
|
+
};
|
51
|
+
}
|
52
|
+
export interface PluginCreateDependenciesResult {
|
53
|
+
type: 'createDependenciesResult';
|
54
|
+
payload: {
|
55
|
+
dependencies: ReturnType<RemotePlugin['createDependencies']>;
|
56
|
+
success: true;
|
57
|
+
} | {
|
58
|
+
success: false;
|
59
|
+
error: string;
|
60
|
+
};
|
61
|
+
}
|
62
|
+
export interface PluginWorkerProcessProjectGraphMessage {
|
63
|
+
type: 'processProjectGraph';
|
64
|
+
payload: {
|
65
|
+
graph: ProjectGraph;
|
66
|
+
ctx: ProjectGraphProcessorContext;
|
67
|
+
};
|
68
|
+
}
|
69
|
+
export interface PluginWorkerProcessProjectGraphResult {
|
70
|
+
type: 'processProjectGraphResult';
|
71
|
+
payload: {
|
72
|
+
graph: ProjectGraph;
|
73
|
+
success: true;
|
74
|
+
} | {
|
75
|
+
success: false;
|
76
|
+
error: string;
|
77
|
+
};
|
78
|
+
}
|
79
|
+
export type PluginWorkerMessage = PluginWorkerLoadMessage | PluginWorkerShutdownMessage | PluginWorkerCreateNodesMessage | PluginCreateDependenciesMessage | PluginWorkerProcessProjectGraphMessage;
|
80
|
+
export type PluginWorkerResult = PluginWorkerLoadResult | PluginWorkerCreateNodesResult | PluginCreateDependenciesResult | PluginWorkerProcessProjectGraphResult;
|
81
|
+
type MaybePromise<T> = T | Promise<T>;
|
82
|
+
type MessageHandlerReturn<T extends PluginWorkerMessage | PluginWorkerResult> = T extends PluginWorkerResult ? MaybePromise<PluginWorkerMessage | void> : MaybePromise<PluginWorkerResult | void>;
|
83
|
+
export declare function consumeMessage<T extends PluginWorkerMessage | PluginWorkerResult>(raw: string | T, handlers: {
|
84
|
+
[K in T['type']]: (payload: Extract<T, {
|
85
|
+
type: K;
|
86
|
+
}>['payload']) => MessageHandlerReturn<T>;
|
87
|
+
}): Promise<void>;
|
88
|
+
export declare function createMessage(message: PluginWorkerMessage | PluginWorkerResult): string;
|
89
|
+
export {};
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.createMessage = exports.consumeMessage = void 0;
|
4
|
+
// Takes a message and a map of handlers and calls the appropriate handler
|
5
|
+
// type safe and requires all handlers to be handled
|
6
|
+
async function consumeMessage(raw, handlers) {
|
7
|
+
const message = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
8
|
+
const handler = handlers[message.type];
|
9
|
+
if (handler) {
|
10
|
+
const response = await handler(message.payload);
|
11
|
+
if (response) {
|
12
|
+
process.send(createMessage(response));
|
13
|
+
}
|
14
|
+
}
|
15
|
+
else {
|
16
|
+
throw new Error(`Unhandled message type: ${message.type}`);
|
17
|
+
}
|
18
|
+
}
|
19
|
+
exports.consumeMessage = consumeMessage;
|
20
|
+
function createMessage(message) {
|
21
|
+
return JSON.stringify(message);
|
22
|
+
}
|
23
|
+
exports.createMessage = createMessage;
|
@@ -0,0 +1,4 @@
|
|
1
|
+
import { PluginConfiguration } from '../../config/nx-json';
|
2
|
+
import { RemotePlugin } from './internal-api';
|
3
|
+
export declare function loadRemoteNxPlugin(plugin: PluginConfiguration, root: string): Promise<RemotePlugin>;
|
4
|
+
export declare function shutdownPluginWorkers(): Promise<any[]>;
|
@@ -0,0 +1,188 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.shutdownPluginWorkers = exports.loadRemoteNxPlugin = void 0;
|
4
|
+
const child_process_1 = require("child_process");
|
5
|
+
const path = require("path");
|
6
|
+
const logger_1 = require("../../utils/logger");
|
7
|
+
const internal_api_1 = require("./internal-api");
|
8
|
+
const messaging_1 = require("./messaging");
|
9
|
+
const pool = [];
|
10
|
+
const pidMap = new Map();
|
11
|
+
function loadRemoteNxPlugin(plugin, root) {
|
12
|
+
// this should only really be true when running unit tests within
|
13
|
+
// the Nx repo. We still need to start the worker in this case,
|
14
|
+
// but its typescript.
|
15
|
+
const isWorkerTypescript = path.extname(__filename) === '.ts';
|
16
|
+
const workerPath = path.join(__dirname, 'plugin-worker');
|
17
|
+
const worker = (0, child_process_1.fork)(workerPath, [], {
|
18
|
+
stdio: ['ignore', 'inherit', 'inherit', 'ipc'],
|
19
|
+
env: {
|
20
|
+
...process.env,
|
21
|
+
...(isWorkerTypescript
|
22
|
+
? {
|
23
|
+
// Ensures that the worker uses the same tsconfig as the main process
|
24
|
+
TS_NODE_PROJECT: path.join(__dirname, '../../../tsconfig.lib.json'),
|
25
|
+
}
|
26
|
+
: {}),
|
27
|
+
},
|
28
|
+
execArgv: [
|
29
|
+
...process.execArgv,
|
30
|
+
// If the worker is typescript, we need to register ts-node
|
31
|
+
...(isWorkerTypescript ? ['-r', 'ts-node/register'] : []),
|
32
|
+
],
|
33
|
+
});
|
34
|
+
worker.send((0, messaging_1.createMessage)({ type: 'load', payload: { plugin, root } }));
|
35
|
+
pool.push(worker);
|
36
|
+
logger_1.logger.verbose(`[plugin-worker] started worker: ${worker.pid}`);
|
37
|
+
return new Promise((res, rej) => {
|
38
|
+
worker.on('message', createWorkerHandler(worker, res, rej));
|
39
|
+
worker.on('exit', () => workerOnExitHandler(worker));
|
40
|
+
});
|
41
|
+
}
|
42
|
+
exports.loadRemoteNxPlugin = loadRemoteNxPlugin;
|
43
|
+
let pluginWorkersShutdown = false;
|
44
|
+
async function shutdownPluginWorkers() {
|
45
|
+
// Clears the plugin cache so no refs to the workers are held
|
46
|
+
internal_api_1.nxPluginCache.clear();
|
47
|
+
// Marks the workers as shutdown so that we don't report unexpected exits
|
48
|
+
pluginWorkersShutdown = true;
|
49
|
+
const promises = [];
|
50
|
+
for (const p of pool) {
|
51
|
+
p.send((0, messaging_1.createMessage)({ type: 'shutdown', payload: undefined }), (error) => {
|
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
|
+
}
|
64
|
+
return Promise.all(promises);
|
65
|
+
}
|
66
|
+
exports.shutdownPluginWorkers = shutdownPluginWorkers;
|
67
|
+
/**
|
68
|
+
* Creates a message handler for the given worker.
|
69
|
+
* @param worker Instance of plugin-worker
|
70
|
+
* @param onload Resolver for RemotePlugin promise
|
71
|
+
* @param onloadError Rejecter for RemotePlugin promise
|
72
|
+
* @returns Function to handle messages from the worker
|
73
|
+
*/
|
74
|
+
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
|
+
let pluginName;
|
89
|
+
return function (message) {
|
90
|
+
const parsed = JSON.parse(message);
|
91
|
+
logger_1.logger.verbose(`[plugin-pool] received message: ${parsed.type} from ${pluginName ?? worker.pid}`);
|
92
|
+
(0, messaging_1.consumeMessage)(parsed, {
|
93
|
+
'load-result': (result) => {
|
94
|
+
if (result.success) {
|
95
|
+
const { name, createNodesPattern } = result;
|
96
|
+
pluginName = name;
|
97
|
+
pidMap.set(worker.pid, name);
|
98
|
+
onload({
|
99
|
+
name,
|
100
|
+
createNodes: createNodesPattern
|
101
|
+
? [
|
102
|
+
createNodesPattern,
|
103
|
+
(configFiles, ctx) => {
|
104
|
+
return new Promise((res, rej) => {
|
105
|
+
worker.send((0, messaging_1.createMessage)({
|
106
|
+
type: 'createNodes',
|
107
|
+
payload: { configFiles, context: ctx },
|
108
|
+
}));
|
109
|
+
createNodesResolver = res;
|
110
|
+
createNodesRejecter = rej;
|
111
|
+
});
|
112
|
+
},
|
113
|
+
]
|
114
|
+
: undefined,
|
115
|
+
createDependencies: result.hasCreateDependencies
|
116
|
+
? (opts, ctx) => {
|
117
|
+
return new Promise((res, rej) => {
|
118
|
+
worker.send((0, messaging_1.createMessage)({
|
119
|
+
type: 'createDependencies',
|
120
|
+
payload: { context: ctx },
|
121
|
+
}));
|
122
|
+
createDependenciesResolver = res;
|
123
|
+
createDependenciesRejecter = rej;
|
124
|
+
});
|
125
|
+
}
|
126
|
+
: undefined,
|
127
|
+
processProjectGraph: result.hasProcessProjectGraph
|
128
|
+
? (graph, ctx) => {
|
129
|
+
return new Promise((res, rej) => {
|
130
|
+
worker.send((0, messaging_1.createMessage)({
|
131
|
+
type: 'processProjectGraph',
|
132
|
+
payload: { graph, ctx },
|
133
|
+
}));
|
134
|
+
processProjectGraphResolver = res;
|
135
|
+
processProjectGraphRejecter = rej;
|
136
|
+
});
|
137
|
+
}
|
138
|
+
: undefined,
|
139
|
+
});
|
140
|
+
}
|
141
|
+
else if (result.success === false) {
|
142
|
+
onloadError(result.error);
|
143
|
+
}
|
144
|
+
},
|
145
|
+
createDependenciesResult: (result) => {
|
146
|
+
if (result.success) {
|
147
|
+
createDependenciesResolver(result.dependencies);
|
148
|
+
createDependenciesResolver = undefined;
|
149
|
+
}
|
150
|
+
else if (result.success === false) {
|
151
|
+
createDependenciesRejecter(result.error);
|
152
|
+
createDependenciesRejecter = undefined;
|
153
|
+
}
|
154
|
+
},
|
155
|
+
createNodesResult: (payload) => {
|
156
|
+
if (payload.success) {
|
157
|
+
createNodesResolver(payload.result);
|
158
|
+
createNodesResolver = undefined;
|
159
|
+
}
|
160
|
+
else if (payload.success === false) {
|
161
|
+
createNodesRejecter(payload.error);
|
162
|
+
createNodesRejecter = undefined;
|
163
|
+
}
|
164
|
+
},
|
165
|
+
processProjectGraphResult: (result) => {
|
166
|
+
if (result.success) {
|
167
|
+
processProjectGraphResolver(result.graph);
|
168
|
+
processProjectGraphResolver = undefined;
|
169
|
+
}
|
170
|
+
else if (result.success === false) {
|
171
|
+
processProjectGraphRejecter(result.error);
|
172
|
+
processProjectGraphRejecter = undefined;
|
173
|
+
}
|
174
|
+
},
|
175
|
+
});
|
176
|
+
};
|
177
|
+
}
|
178
|
+
function workerOnExitHandler(worker) {
|
179
|
+
return () => {
|
180
|
+
if (!pluginWorkersShutdown) {
|
181
|
+
shutdownPluginWorkers();
|
182
|
+
throw new Error(`[Nx] plugin worker ${pidMap.get(worker.pid) ?? worker.pid} exited unexpectedly`);
|
183
|
+
}
|
184
|
+
};
|
185
|
+
}
|
186
|
+
process.on('exit', () => {
|
187
|
+
shutdownPluginWorkers();
|
188
|
+
});
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,122 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const installation_directory_1 = require("../../utils/installation-directory");
|
4
|
+
const worker_api_1 = require("./worker-api");
|
5
|
+
const messaging_1 = require("./messaging");
|
6
|
+
const retrieve_workspace_files_1 = require("../utils/retrieve-workspace-files");
|
7
|
+
global.NX_GRAPH_CREATION = true;
|
8
|
+
let plugin;
|
9
|
+
let pluginOptions;
|
10
|
+
process.on('message', async (message) => {
|
11
|
+
(0, messaging_1.consumeMessage)(message, {
|
12
|
+
load: async ({ plugin: pluginConfiguration, root }) => {
|
13
|
+
process.chdir(root);
|
14
|
+
try {
|
15
|
+
({ plugin, options: pluginOptions } = await loadPluginFromWorker(pluginConfiguration, root));
|
16
|
+
return {
|
17
|
+
type: 'load-result',
|
18
|
+
payload: {
|
19
|
+
name: plugin.name,
|
20
|
+
createNodesPattern: plugin.createNodes?.[0],
|
21
|
+
hasCreateDependencies: 'createDependencies' in plugin && !!plugin.createDependencies,
|
22
|
+
hasProcessProjectGraph: 'processProjectGraph' in plugin && !!plugin.processProjectGraph,
|
23
|
+
success: true,
|
24
|
+
},
|
25
|
+
};
|
26
|
+
}
|
27
|
+
catch (e) {
|
28
|
+
return {
|
29
|
+
type: 'load-result',
|
30
|
+
payload: {
|
31
|
+
success: false,
|
32
|
+
error: `Could not load plugin ${plugin} \n ${e instanceof Error ? e.stack : ''}`,
|
33
|
+
},
|
34
|
+
};
|
35
|
+
}
|
36
|
+
},
|
37
|
+
shutdown: async () => {
|
38
|
+
process.exit(0);
|
39
|
+
},
|
40
|
+
createNodes: async ({ configFiles, context }) => {
|
41
|
+
try {
|
42
|
+
const result = await runCreateNodesInParallel(configFiles, context);
|
43
|
+
return {
|
44
|
+
type: 'createNodesResult',
|
45
|
+
payload: { result, success: true },
|
46
|
+
};
|
47
|
+
}
|
48
|
+
catch (e) {
|
49
|
+
return {
|
50
|
+
type: 'createNodesResult',
|
51
|
+
payload: { success: false, error: e.stack },
|
52
|
+
};
|
53
|
+
}
|
54
|
+
},
|
55
|
+
createDependencies: async (payload) => {
|
56
|
+
try {
|
57
|
+
const result = await plugin.createDependencies(pluginOptions, payload.context);
|
58
|
+
return {
|
59
|
+
type: 'createDependenciesResult',
|
60
|
+
payload: { dependencies: result, success: true },
|
61
|
+
};
|
62
|
+
}
|
63
|
+
catch (e) {
|
64
|
+
return {
|
65
|
+
type: 'createDependenciesResult',
|
66
|
+
payload: { success: false, error: e.stack },
|
67
|
+
};
|
68
|
+
}
|
69
|
+
},
|
70
|
+
processProjectGraph: async ({ graph, ctx }) => {
|
71
|
+
try {
|
72
|
+
const result = await plugin.processProjectGraph(graph, ctx);
|
73
|
+
return {
|
74
|
+
type: 'processProjectGraphResult',
|
75
|
+
payload: { graph: result, success: true },
|
76
|
+
};
|
77
|
+
}
|
78
|
+
catch (e) {
|
79
|
+
return {
|
80
|
+
type: 'processProjectGraphResult',
|
81
|
+
payload: { success: false, error: e.stack },
|
82
|
+
};
|
83
|
+
}
|
84
|
+
},
|
85
|
+
});
|
86
|
+
});
|
87
|
+
let projectsWithoutInference;
|
88
|
+
async function loadPluginFromWorker(plugin, root) {
|
89
|
+
try {
|
90
|
+
require.resolve(typeof plugin === 'string' ? plugin : plugin.plugin);
|
91
|
+
}
|
92
|
+
catch {
|
93
|
+
// If a plugin cannot be resolved, we will need projects to resolve it
|
94
|
+
projectsWithoutInference ??=
|
95
|
+
await (0, retrieve_workspace_files_1.retrieveProjectConfigurationsWithoutPluginInference)(root);
|
96
|
+
}
|
97
|
+
return await (0, worker_api_1.loadNxPluginAsync)(plugin, (0, installation_directory_1.getNxRequirePaths)(root), projectsWithoutInference, root);
|
98
|
+
}
|
99
|
+
function runCreateNodesInParallel(configFiles, context) {
|
100
|
+
const promises = configFiles.map((file) => {
|
101
|
+
performance.mark(`${plugin.name}:createNodes:${file} - start`);
|
102
|
+
const value = plugin.createNodes[1](file, pluginOptions, context);
|
103
|
+
if (value instanceof Promise) {
|
104
|
+
return value
|
105
|
+
.catch((e) => {
|
106
|
+
performance.mark(`${plugin.name}:createNodes:${file} - end`);
|
107
|
+
throw new Error(`Unable to create nodes for ${file} using plugin ${plugin.name}.`, e);
|
108
|
+
})
|
109
|
+
.then((r) => {
|
110
|
+
performance.mark(`${plugin.name}:createNodes:${file} - end`);
|
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 {
|
116
|
+
performance.mark(`${plugin.name}:createNodes:${file} - end`);
|
117
|
+
performance.measure(`${plugin.name}:createNodes:${file}`, `${plugin.name}:createNodes:${file} - start`, `${plugin.name}:createNodes:${file} - end`);
|
118
|
+
return { ...value, pluginName: plugin.name, file };
|
119
|
+
}
|
120
|
+
});
|
121
|
+
return Promise.all(promises);
|
122
|
+
}
|