Skip to content

Commit c21b039

Browse files
authored
fix(core): reduce time it takes to require nx commands (#28884)
<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> `nx/src/command-line/nx-commands` takes ~88-91ms on my machine to require which needs to happen for every single Nx command. ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> `nx/src/command-line/nx-commands` takes ~30-33ms on my machine to require. ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
1 parent 19b0828 commit c21b039

File tree

9 files changed

+149
-151
lines changed

9 files changed

+149
-151
lines changed

packages/nx/src/command-line/generate/command-object.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { CommandModule, Argv } from 'yargs';
2-
import { getCwd } from '../../utils/path';
3-
import { linkToNxDevAndExamples } from '../yargs-utils/documentation';
1+
import { Argv, CommandModule } from 'yargs';
42
import { withVerbose } from '../yargs-utils/shared-options';
53

64
export const yargsGenerateCommand: CommandModule = {
@@ -13,7 +11,7 @@ export const yargsGenerateCommand: CommandModule = {
1311
// Remove the command from the args
1412
args._ = args._.slice(1);
1513

16-
process.exit(await (await import('./generate')).generate(getCwd(), args));
14+
process.exit(await (await import('./generate')).generate(args));
1715
},
1816
};
1917

packages/nx/src/command-line/generate/generate.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { workspaceRoot } from '../../utils/workspace-root';
2222
import { calculateDefaultProjectName } from '../../config/calculate-default-project-name';
2323
import { findInstalledPlugins } from '../../utils/plugins/installed-plugins';
2424
import { getGeneratorInformation } from './generator-utils';
25+
import { getCwd } from '../../utils/path';
2526

2627
export interface GenerateOptions {
2728
collectionName: string;
@@ -300,7 +301,7 @@ export function printGenHelp(
300301
);
301302
}
302303

303-
export async function generate(cwd: string, args: { [k: string]: any }) {
304+
export async function generate(args: { [k: string]: any }) {
304305
return handleErrors(args.verbose, async () => {
305306
const nxJsonConfiguration = readNxJson();
306307
const projectGraph = await createProjectGraphAsync();
@@ -348,6 +349,8 @@ export async function generate(cwd: string, args: { [k: string]: any }) {
348349
return 0;
349350
}
350351

352+
const cwd = getCwd();
353+
351354
const combinedOpts = await combineOptionsForGenerator(
352355
opts.generatorOptions,
353356
opts.collectionName,

packages/nx/src/command-line/init/command-object.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import { Argv, CommandModule } from 'yargs';
22
import { parseCSV } from '../yargs-utils/shared-options';
3-
import { readNxJson } from '../../config/nx-json';
4-
5-
const useV2 =
6-
process.env['NX_ADD_PLUGINS'] !== 'false' &&
7-
readNxJson().useInferencePlugins !== false;
83

94
export const yargsInitCommand: CommandModule = {
105
command: 'init',
116
describe:
127
'Adds Nx to any type of workspace. It installs nx, creates an nx.json configuration file and optionally sets up remote caching. For more info, check https://nx.dev/recipes/adopting-nx.',
138
builder: (yargs) => withInitOptions(yargs),
149
handler: async (args: any) => {
10+
const useV2 = await isInitV2();
1511
if (useV2) {
1612
await require('./init-v2').initHandler(args);
1713
} else {
@@ -21,7 +17,16 @@ export const yargsInitCommand: CommandModule = {
2117
},
2218
};
2319

24-
function withInitOptions(yargs: Argv) {
20+
async function isInitV2() {
21+
return (
22+
process.env['NX_ADD_PLUGINS'] !== 'false' &&
23+
(await import('../../config/nx-json')).readNxJson().useInferencePlugins !==
24+
false
25+
);
26+
}
27+
28+
async function withInitOptions(yargs: Argv) {
29+
const useV2 = await isInitV2();
2530
if (useV2) {
2631
return yargs
2732
.option('nxCloud', {
Lines changed: 2 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
import { Argv, CommandModule } from 'yargs';
2-
import * as path from 'path';
3-
import { runNxSync } from '../../utils/child-process';
42
import { linkToNxDevAndExamples } from '../yargs-utils/documentation';
5-
import { execSync } from 'child_process';
6-
import {
7-
copyPackageManagerConfigurationFiles,
8-
detectPackageManager,
9-
getPackageManagerCommand,
10-
} from '../../utils/package-manager';
11-
import { writeJsonFile } from '../../utils/fileutils';
12-
import { workspaceRoot } from '../../utils/workspace-root';
133
import { withVerbose } from '../yargs-utils/shared-options';
144

155
export const yargsMigrateCommand: CommandModule = {
@@ -19,8 +9,8 @@ export const yargsMigrateCommand: CommandModule = {
199
- Run migrations (e.g., nx migrate --run-migrations=migrations.json). Use flag --if-exists to run migrations only if the migrations file exists.`,
2010
builder: (yargs) =>
2111
linkToNxDevAndExamples(withMigrationOptions(yargs), 'migrate'),
22-
handler: () => {
23-
runMigration();
12+
handler: async () => {
13+
(await import('./migrate')).runMigration();
2414
process.exit(0);
2515
},
2616
};
@@ -104,104 +94,3 @@ function withMigrationOptions(yargs: Argv) {
10494
}
10595
);
10696
}
107-
108-
function runMigration() {
109-
const runLocalMigrate = () => {
110-
runNxSync(`_migrate ${process.argv.slice(3).join(' ')}`, {
111-
stdio: ['inherit', 'inherit', 'inherit'],
112-
});
113-
};
114-
if (process.env.NX_MIGRATE_USE_LOCAL === undefined) {
115-
const p = nxCliPath();
116-
if (p === null) {
117-
runLocalMigrate();
118-
} else {
119-
// ensure local registry from process is not interfering with the install
120-
// when we start the process from temp folder the local registry would override the custom registry
121-
if (
122-
process.env.npm_config_registry &&
123-
process.env.npm_config_registry.match(
124-
/^https:\/\/registry\.(npmjs\.org|yarnpkg\.com)/
125-
)
126-
) {
127-
delete process.env.npm_config_registry;
128-
}
129-
execSync(`${p} _migrate ${process.argv.slice(3).join(' ')}`, {
130-
stdio: ['inherit', 'inherit', 'inherit'],
131-
windowsHide: false,
132-
});
133-
}
134-
} else {
135-
runLocalMigrate();
136-
}
137-
}
138-
139-
function nxCliPath() {
140-
const version = process.env.NX_MIGRATE_CLI_VERSION || 'latest';
141-
try {
142-
const packageManager = detectPackageManager();
143-
const pmc = getPackageManagerCommand(packageManager);
144-
145-
const { dirSync } = require('tmp');
146-
const tmpDir = dirSync().name;
147-
writeJsonFile(path.join(tmpDir, 'package.json'), {
148-
dependencies: {
149-
nx: version,
150-
},
151-
license: 'MIT',
152-
});
153-
copyPackageManagerConfigurationFiles(workspaceRoot, tmpDir);
154-
if (pmc.preInstall) {
155-
// ensure package.json and repo in tmp folder is set to a proper package manager state
156-
execSync(pmc.preInstall, {
157-
cwd: tmpDir,
158-
stdio: ['ignore', 'ignore', 'ignore'],
159-
windowsHide: false,
160-
});
161-
// if it's berry ensure we set the node_linker to node-modules
162-
if (packageManager === 'yarn' && pmc.ciInstall.includes('immutable')) {
163-
execSync('yarn config set nodeLinker node-modules', {
164-
cwd: tmpDir,
165-
stdio: ['ignore', 'ignore', 'ignore'],
166-
windowsHide: false,
167-
});
168-
}
169-
}
170-
171-
execSync(pmc.install, {
172-
cwd: tmpDir,
173-
stdio: ['ignore', 'ignore', 'ignore'],
174-
windowsHide: false,
175-
});
176-
177-
// Set NODE_PATH so that these modules can be used for module resolution
178-
addToNodePath(path.join(tmpDir, 'node_modules'));
179-
addToNodePath(path.join(workspaceRoot, 'node_modules'));
180-
181-
return path.join(tmpDir, `node_modules`, '.bin', 'nx');
182-
} catch (e) {
183-
console.error(
184-
`Failed to install the ${version} version of the migration script. Using the current version.`
185-
);
186-
if (process.env.NX_VERBOSE_LOGGING === 'true') {
187-
console.error(e);
188-
}
189-
return null;
190-
}
191-
}
192-
193-
function addToNodePath(dir: string) {
194-
// NODE_PATH is a delimited list of paths.
195-
// The delimiter is different for windows.
196-
const delimiter = require('os').platform() === 'win32' ? ';' : ':';
197-
198-
const paths = process.env.NODE_PATH
199-
? process.env.NODE_PATH.split(delimiter)
200-
: [];
201-
202-
// Add the tmp path
203-
paths.push(dir);
204-
205-
// Update the env variable.
206-
process.env.NODE_PATH = paths.join(delimiter);
207-
}

packages/nx/src/command-line/migrate/migrate.ts

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
readNxMigrateConfig,
4343
} from '../../utils/package-json';
4444
import {
45+
copyPackageManagerConfigurationFiles,
4546
createTempNpmDirectory,
4647
detectPackageManager,
4748
getPackageManagerCommand,
@@ -55,7 +56,7 @@ import {
5556
onlyDefaultRunnerIsUsed,
5657
} from '../connect/connect-to-nx-cloud';
5758
import { output } from '../../utils/output';
58-
import { existsSync, readFileSync, writeFileSync } from 'fs';
59+
import { existsSync, writeFileSync } from 'fs';
5960
import { workspaceRoot } from '../../utils/workspace-root';
6061
import { isCI } from '../../utils/is-ci';
6162
import { getNxRequirePaths } from '../../utils/installation-directory';
@@ -68,6 +69,7 @@ import {
6869
readProjectsConfigurationFromProjectGraph,
6970
} from '../../project-graph/project-graph';
7071
import { formatFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
72+
import { dirSync } from 'tmp';
7173

7274
export interface ResolvedMigrationConfiguration extends MigrationsJson {
7375
packageGroup?: ArrayPackageGroup;
@@ -1655,6 +1657,37 @@ export async function migrate(
16551657
});
16561658
}
16571659

1660+
export function runMigration() {
1661+
const runLocalMigrate = () => {
1662+
runNxSync(`_migrate ${process.argv.slice(3).join(' ')}`, {
1663+
stdio: ['inherit', 'inherit', 'inherit'],
1664+
});
1665+
};
1666+
if (process.env.NX_MIGRATE_USE_LOCAL === undefined) {
1667+
const p = nxCliPath();
1668+
if (p === null) {
1669+
runLocalMigrate();
1670+
} else {
1671+
// ensure local registry from process is not interfering with the install
1672+
// when we start the process from temp folder the local registry would override the custom registry
1673+
if (
1674+
process.env.npm_config_registry &&
1675+
process.env.npm_config_registry.match(
1676+
/^https:\/\/registry\.(npmjs\.org|yarnpkg\.com)/
1677+
)
1678+
) {
1679+
delete process.env.npm_config_registry;
1680+
}
1681+
execSync(`${p} _migrate ${process.argv.slice(3).join(' ')}`, {
1682+
stdio: ['inherit', 'inherit', 'inherit'],
1683+
windowsHide: false,
1684+
});
1685+
}
1686+
} else {
1687+
runLocalMigrate();
1688+
}
1689+
}
1690+
16581691
function readMigrationCollection(packageName: string, root: string) {
16591692
const collectionPath = readPackageMigrationConfig(
16601693
packageName,
@@ -1699,6 +1732,76 @@ function getImplementationPath(
16991732
return { path: implPath, fnSymbol };
17001733
}
17011734

1735+
function nxCliPath() {
1736+
const version = process.env.NX_MIGRATE_CLI_VERSION || 'latest';
1737+
try {
1738+
const packageManager = detectPackageManager();
1739+
const pmc = getPackageManagerCommand(packageManager);
1740+
1741+
const { dirSync } = require('tmp');
1742+
const tmpDir = dirSync().name;
1743+
writeJsonFile(join(tmpDir, 'package.json'), {
1744+
dependencies: {
1745+
nx: version,
1746+
},
1747+
license: 'MIT',
1748+
});
1749+
copyPackageManagerConfigurationFiles(workspaceRoot, tmpDir);
1750+
if (pmc.preInstall) {
1751+
// ensure package.json and repo in tmp folder is set to a proper package manager state
1752+
execSync(pmc.preInstall, {
1753+
cwd: tmpDir,
1754+
stdio: ['ignore', 'ignore', 'ignore'],
1755+
windowsHide: false,
1756+
});
1757+
// if it's berry ensure we set the node_linker to node-modules
1758+
if (packageManager === 'yarn' && pmc.ciInstall.includes('immutable')) {
1759+
execSync('yarn config set nodeLinker node-modules', {
1760+
cwd: tmpDir,
1761+
stdio: ['ignore', 'ignore', 'ignore'],
1762+
windowsHide: false,
1763+
});
1764+
}
1765+
}
1766+
1767+
execSync(pmc.install, {
1768+
cwd: tmpDir,
1769+
stdio: ['ignore', 'ignore', 'ignore'],
1770+
windowsHide: false,
1771+
});
1772+
1773+
// Set NODE_PATH so that these modules can be used for module resolution
1774+
addToNodePath(join(tmpDir, 'node_modules'));
1775+
addToNodePath(join(workspaceRoot, 'node_modules'));
1776+
1777+
return join(tmpDir, `node_modules`, '.bin', 'nx');
1778+
} catch (e) {
1779+
console.error(
1780+
`Failed to install the ${version} version of the migration script. Using the current version.`
1781+
);
1782+
if (process.env.NX_VERBOSE_LOGGING === 'true') {
1783+
console.error(e);
1784+
}
1785+
return null;
1786+
}
1787+
}
1788+
1789+
function addToNodePath(dir: string) {
1790+
// NODE_PATH is a delimited list of paths.
1791+
// The delimiter is different for windows.
1792+
const delimiter = require('os').platform() === 'win32' ? ';' : ':';
1793+
1794+
const paths = process.env.NODE_PATH
1795+
? process.env.NODE_PATH.split(delimiter)
1796+
: [];
1797+
1798+
// Add the tmp path
1799+
paths.push(dir);
1800+
1801+
// Update the env variable.
1802+
process.env.NODE_PATH = paths.join(delimiter);
1803+
}
1804+
17021805
// TODO (v21): Remove CLI determination of Angular Migration
17031806
function isAngularMigration(
17041807
collection: MigrationsJson,

packages/nx/src/command-line/release/command-object.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import { Argv, CommandModule, showHelp } from 'yargs';
2-
import { readNxJson } from '../../config/nx-json';
3-
import { readParallelFromArgsAndEnv } from '../../utils/command-line-utils';
42
import { logger } from '../../utils/logger';
53
import {
64
OutputStyle,
@@ -11,6 +9,7 @@ import {
119
withOverrides,
1210
withRunManyOptions,
1311
withVerbose,
12+
readParallelFromArgsAndEnv,
1413
} from '../yargs-utils/shared-options';
1514
import { VersionData } from './utils/shared';
1615

@@ -151,13 +150,13 @@ export const yargsReleaseCommand: CommandModule<
151150
return val;
152151
},
153152
})
154-
.check((argv) => {
153+
.check(async (argv) => {
155154
if (argv.groups && argv.projects) {
156155
throw new Error(
157156
'The --projects and --groups options are mutually exclusive, please use one or the other.'
158157
);
159158
}
160-
const nxJson = readNxJson();
159+
const nxJson = (await import('../../config/nx-json')).readNxJson();
161160
if (argv.groups?.length) {
162161
for (const group of argv.groups) {
163162
if (!nxJson.release?.groups?.[group]) {

0 commit comments

Comments
 (0)