/
githubmirror
/
angular-cli
Обзор
Документация
Войти
/
githubmirror
/
angular-cli
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/angular/cli/lib/init.ts
174 строки
6 KB
Charles Lyding
perf(@angular/cli): avoid eager module loading during global bootstrap
07 авг 2026, 21:16
07 авг 2026, 21:16
2e4dd90
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import { readFile } from 'node:fs/promises'; import { createRequire } from 'node:module'; import * as path from 'node:path'; import { SemVer, major } from 'semver'; import { disableVersionCheck } from '../src/utilities/environment-options'; import { VERSION } from '../src/utilities/version'; /** * Angular CLI versions prior to v14 may not exit correctly if not forcibly exited * via `process.exit()`. When bootstrapping, `forceExit` will be set to `true` * if the local CLI version is less than v14 to prevent the CLI from hanging on * exit in those cases. */ let forceExit = false; (async (): Promise<typeof import('./cli').default | null> => { /** * On Windows, ensure process.cwd() uses uppercase drive letter casing. * Windows cmd.exe and VS Code terminals often preserve lowercase drive letters (e.g. c:\...), * which causes ESM module duplication in Node.js (e.g. loading "vitest" twice) and path * lookup mismatches in tools like Vite and esbuild. */ if (process.platform === 'win32') { const cwd = process.cwd(); if (/^[a-z]:/.test(cwd)) { try { process.chdir(cwd[0].toUpperCase() + cwd.slice(1)); } catch { // Ignore failure to change directory } } // Ensure Windows CreateProcess does not search the current directory for bare executable names. process.env['NoDefaultCurrentDirectoryInExePath'] = '1'; } /** * Disable Browserslist old data warning as otherwise with every release we'd need to update this dependency * which is cumbersome considering we pin versions and the warning is not user actionable. * `Browserslist: caniuse-lite is outdated. Please run next command `npm update` * See: https://github.com/browserslist/browserslist/blob/819c4337456996d19db6ba953014579329e9c6e1/node.js#L324 */ process.env.BROWSERSLIST_IGNORE_OLD_DATA = '1'; const rawCommandName = process.argv[2]; /** * Disable CLI version mismatch checks and forces usage of the invoked CLI * instead of invoking the local installed version. * * When running `ng new` always favor the global version. As in some * cases orphan `node_modules` would cause the non global CLI to be used. * @see: https://github.com/angular/angular-cli/issues/14603 */ if (disableVersionCheck || rawCommandName === 'new') { return (await import('./cli')).default; } let cli; try { // No error implies a projectLocalCli, which will load whatever // version of ng-cli you have installed in a local package.json const cwdRequire = createRequire(process.cwd() + '/'); const projectLocalCli = cwdRequire.resolve('@angular/cli'); cli = await import(projectLocalCli); const globalVersion = new SemVer(VERSION.full); // Older versions might not have the VERSION export let localVersion = cli.VERSION?.full; if (!localVersion) { try { const localPackageJson = await readFile( path.join(path.dirname(projectLocalCli), '../../package.json'), 'utf-8', ); localVersion = (JSON.parse(localPackageJson) as { version: string }).version; } catch (error) { // eslint-disable-next-line no-console console.error('Version mismatch check skipped. Unable to retrieve local version: ' + error); } } // Ensure older versions of the CLI fully exit const localMajorVersion = major(localVersion); if (localMajorVersion > 0 && localMajorVersion < 14) { forceExit = true; // Versions prior to 14 didn't implement completion command. if (rawCommandName === 'completion') { return null; } } let isGlobalGreater = false; try { isGlobalGreater = localVersion > 0 && globalVersion.compare(localVersion) > 0; } catch (error) { // eslint-disable-next-line no-console console.error('Version mismatch check skipped. Unable to compare local version: ' + error); } // When using the completion command, don't show the warning as otherwise this will break completion. if ( isGlobalGreater && rawCommandName !== '--get-yargs-completions' && rawCommandName !== 'completion' ) { // If using the update command and the global version is greater, use the newer update command // This allows improvements in update to be used in older versions that do not have bootstrapping if ( rawCommandName === 'update' && cli.VERSION && cli.VERSION.major - globalVersion.major <= 1 ) { cli = await import('./cli'); } else { try { const { isWarningEnabled } = await import('../src/utilities/config'); if (await isWarningEnabled('versionMismatch')) { // Otherwise, use local version and warn if global is newer than local const warning = `Your global Angular CLI version (${globalVersion}) is greater than your local ` + `version (${localVersion}). The local Angular CLI version is used.\n\n` + 'To disable this warning use "ng config -g cli.warnings.versionMismatch false".'; const { colors } = await import('../src/utilities/color'); // eslint-disable-next-line no-console console.error(colors.yellow(warning)); } } catch { // Ignore errors during warning check to avoid falling back to global CLI } } } } catch { // If there is an error, resolve could not find the ng-cli // library from a package.json. Instead, include it from a relative // path to this script file (which is likely a globally installed // npm package). Most common cause for hitting this is `ng new` cli = await import('./cli'); } if ('default' in cli) { cli = cli['default']; } return cli; })() .then((cli) => cli?.({ cliArgs: process.argv.slice(2), }), ) .then((exitCode = 0) => { if (forceExit) { process.exit(exitCode); } process.exitCode = exitCode; }) .catch((err: Error) => { // eslint-disable-next-line no-console console.error('Unknown error: ' + err.toString()); process.exit(127); });