From f9b2fb1c4981ff138992a502d3aba4f6a3886df4 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Thu, 13 Apr 2023 15:18:37 +0000 Subject: [PATCH] perf(@angular/cli): register CLI commands lazily MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently there is a lot of overhead coming from requiring external modules when registering commands such as `ng update` and `ng add`. This is because these commands do not lazily require all the modules causes the resolution of unneeded packages to be part of the critical path. With this change we "require” only the command that we we need to execute, which reduce the number of node modules resolutions in the critical path. (cherry picked from commit 5b62074ec2e69c7410242bf26584d8a7ef731fbf) --- .../cli/src/command-builder/command-runner.ts | 75 +++++------- .../src/command-builder/utilities/command.ts | 14 ++- packages/angular/cli/src/commands/add/cli.ts | 2 +- .../angular/cli/src/commands/analytics/cli.ts | 5 +- .../angular/cli/src/commands/build/cli.ts | 5 +- .../angular/cli/src/commands/cache/cli.ts | 5 +- .../cli/src/commands/command-config.ts | 114 ++++++++++++++++++ .../cli/src/commands/completion/cli.ts | 5 +- .../angular/cli/src/commands/config/cli.ts | 2 +- .../angular/cli/src/commands/deploy/cli.ts | 2 +- packages/angular/cli/src/commands/doc/cli.ts | 5 +- packages/angular/cli/src/commands/e2e/cli.ts | 5 +- .../cli/src/commands/extract-i18n/cli.ts | 2 +- .../angular/cli/src/commands/generate/cli.ts | 5 +- packages/angular/cli/src/commands/lint/cli.ts | 2 +- .../cli/src/commands/make-this-awesome/cli.ts | 5 +- packages/angular/cli/src/commands/new/cli.ts | 5 +- packages/angular/cli/src/commands/run/cli.ts | 2 +- .../angular/cli/src/commands/serve/cli.ts | 5 +- packages/angular/cli/src/commands/test/cli.ts | 5 +- .../angular/cli/src/commands/update/cli.ts | 2 +- .../angular/cli/src/commands/version/cli.ts | 8 +- 22 files changed, 204 insertions(+), 76 deletions(-) create mode 100644 packages/angular/cli/src/commands/command-config.ts diff --git a/packages/angular/cli/src/command-builder/command-runner.ts b/packages/angular/cli/src/command-builder/command-runner.ts index 36c4b308ecc6..bacf9ac98626 100644 --- a/packages/angular/cli/src/command-builder/command-runner.ts +++ b/packages/angular/cli/src/command-builder/command-runner.ts @@ -9,56 +9,25 @@ import { logging } from '@angular-devkit/core'; import yargs from 'yargs'; import { Parser } from 'yargs/helpers'; -import { AddCommandModule } from '../commands/add/cli'; -import { AnalyticsCommandModule } from '../commands/analytics/cli'; -import { BuildCommandModule } from '../commands/build/cli'; -import { CacheCommandModule } from '../commands/cache/cli'; -import { CompletionCommandModule } from '../commands/completion/cli'; -import { ConfigCommandModule } from '../commands/config/cli'; -import { DeployCommandModule } from '../commands/deploy/cli'; -import { DocCommandModule } from '../commands/doc/cli'; -import { E2eCommandModule } from '../commands/e2e/cli'; -import { ExtractI18nCommandModule } from '../commands/extract-i18n/cli'; -import { GenerateCommandModule } from '../commands/generate/cli'; -import { LintCommandModule } from '../commands/lint/cli'; -import { AwesomeCommandModule } from '../commands/make-this-awesome/cli'; -import { NewCommandModule } from '../commands/new/cli'; -import { RunCommandModule } from '../commands/run/cli'; -import { ServeCommandModule } from '../commands/serve/cli'; -import { TestCommandModule } from '../commands/test/cli'; -import { UpdateCommandModule } from '../commands/update/cli'; -import { VersionCommandModule } from '../commands/version/cli'; +import { + CommandConfig, + CommandNames, + RootCommands, + RootCommandsAliases, +} from '../commands/command-config'; import { colors } from '../utilities/color'; import { AngularWorkspace, getWorkspace } from '../utilities/config'; import { assertIsError } from '../utilities/error'; import { PackageManagerUtils } from '../utilities/package-manager'; import { CommandContext, CommandModuleError } from './command-module'; -import { addCommandModuleToYargs, demandCommandFailureMessage } from './utilities/command'; +import { + CommandModuleConstructor, + addCommandModuleToYargs, + demandCommandFailureMessage, +} from './utilities/command'; import { jsonHelpUsage } from './utilities/json-help'; import { normalizeOptionsMiddleware } from './utilities/normalize-options-middleware'; -const COMMANDS = [ - VersionCommandModule, - DocCommandModule, - AwesomeCommandModule, - ConfigCommandModule, - AnalyticsCommandModule, - AddCommandModule, - GenerateCommandModule, - BuildCommandModule, - E2eCommandModule, - TestCommandModule, - ServeCommandModule, - ExtractI18nCommandModule, - DeployCommandModule, - LintCommandModule, - NewCommandModule, - UpdateCommandModule, - RunCommandModule, - CacheCommandModule, - CompletionCommandModule, -].sort(); // Will be sorted by class name. - const yargsParser = Parser as unknown as typeof Parser.default; export async function runCommand(args: string[], logger: logging.Logger): Promise { @@ -111,7 +80,7 @@ export async function runCommand(args: string[], logger: logging.Logger): Promis }; let localYargs = yargs(args); - for (const CommandModule of COMMANDS) { + for (const CommandModule of await getCommandsToRegister(positional[0])) { localYargs = addCommandModuleToYargs(localYargs, CommandModule, context); } @@ -168,3 +137,23 @@ export async function runCommand(args: string[], logger: logging.Logger): Promis return process.exitCode ?? 0; } + +/** + * Get the commands that need to be registered. + * @returns One or more command factories that needs to be registered. + */ +async function getCommandsToRegister( + commandName: string | number, +): Promise { + const commands: CommandConfig[] = []; + if (commandName in RootCommands) { + commands.push(RootCommands[commandName as CommandNames]); + } else if (commandName in RootCommandsAliases) { + commands.push(RootCommandsAliases[commandName]); + } else { + // Unknown command, register every possible command. + Object.values(RootCommands).forEach((c) => commands.push(c)); + } + + return Promise.all(commands.map((command) => command.factory().then((m) => m.default))); +} diff --git a/packages/angular/cli/src/command-builder/utilities/command.ts b/packages/angular/cli/src/command-builder/utilities/command.ts index 3c3a1fa566ad..5ba067e38209 100644 --- a/packages/angular/cli/src/command-builder/utilities/command.ts +++ b/packages/angular/cli/src/command-builder/utilities/command.ts @@ -16,13 +16,15 @@ import { } from '../command-module'; export const demandCommandFailureMessage = `You need to specify a command before moving on. Use '--help' to view the available commands.`; +export type CommandModuleConstructor = Partial & { + new (context: CommandContext): Partial & CommandModule; +}; -export function addCommandModuleToYargs< - T extends object, - U extends Partial & { - new (context: CommandContext): Partial & CommandModule; - }, ->(localYargs: Argv, commandModule: U, context: CommandContext): Argv { +export function addCommandModuleToYargs( + localYargs: Argv, + commandModule: U, + context: CommandContext, +): Argv { const cmd = new commandModule(context); const { args: { diff --git a/packages/angular/cli/src/commands/add/cli.ts b/packages/angular/cli/src/commands/add/cli.ts index 16bcc2d9f30a..4c964a422969 100644 --- a/packages/angular/cli/src/commands/add/cli.ts +++ b/packages/angular/cli/src/commands/add/cli.ts @@ -55,7 +55,7 @@ const packageVersionExclusions: Record = { '@angular/material': '7.x', }; -export class AddCommandModule +export default class AddCommadModule extends SchematicsCommandModule implements CommandModuleImplementation { diff --git a/packages/angular/cli/src/commands/analytics/cli.ts b/packages/angular/cli/src/commands/analytics/cli.ts index bdba1ccafd11..8e3753ababb1 100644 --- a/packages/angular/cli/src/commands/analytics/cli.ts +++ b/packages/angular/cli/src/commands/analytics/cli.ts @@ -24,7 +24,10 @@ import { AnalyticsPromptModule, } from './settings/cli'; -export class AnalyticsCommandModule extends CommandModule implements CommandModuleImplementation { +export default class AnalyticsCommandModule + extends CommandModule + implements CommandModuleImplementation +{ command = 'analytics'; describe = 'Configures the gathering of Angular CLI usage metrics.'; longDescriptionPath = join(__dirname, 'long-description.md'); diff --git a/packages/angular/cli/src/commands/build/cli.ts b/packages/angular/cli/src/commands/build/cli.ts index 434ff4f22f84..196585a4b122 100644 --- a/packages/angular/cli/src/commands/build/cli.ts +++ b/packages/angular/cli/src/commands/build/cli.ts @@ -9,14 +9,15 @@ import { join } from 'path'; import { ArchitectCommandModule } from '../../command-builder/architect-command-module'; import { CommandModuleImplementation } from '../../command-builder/command-module'; +import { RootCommands } from '../command-config'; -export class BuildCommandModule +export default class BuildCommandModule extends ArchitectCommandModule implements CommandModuleImplementation { multiTarget = false; command = 'build [project]'; - aliases = ['b']; + aliases = RootCommands['build'].aliases; describe = 'Compiles an Angular application or library into an output directory named dist/ at the given output path.'; longDescriptionPath = join(__dirname, 'long-description.md'); diff --git a/packages/angular/cli/src/commands/cache/cli.ts b/packages/angular/cli/src/commands/cache/cli.ts index f30c4acd3b81..bc4115d8cfde 100644 --- a/packages/angular/cli/src/commands/cache/cli.ts +++ b/packages/angular/cli/src/commands/cache/cli.ts @@ -22,7 +22,10 @@ import { CacheCleanModule } from './clean/cli'; import { CacheInfoCommandModule } from './info/cli'; import { CacheDisableModule, CacheEnableModule } from './settings/cli'; -export class CacheCommandModule extends CommandModule implements CommandModuleImplementation { +export default class CacheCommandModule + extends CommandModule + implements CommandModuleImplementation +{ command = 'cache'; describe = 'Configure persistent disk cache and retrieve cache statistics.'; longDescriptionPath = join(__dirname, 'long-description.md'); diff --git a/packages/angular/cli/src/commands/command-config.ts b/packages/angular/cli/src/commands/command-config.ts new file mode 100644 index 000000000000..4cbe2bbb1a73 --- /dev/null +++ b/packages/angular/cli/src/commands/command-config.ts @@ -0,0 +1,114 @@ +/** + * @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.io/license + */ + +import { CommandModuleConstructor } from '../command-builder/utilities/command'; + +export type CommandNames = + | 'add' + | 'analytics' + | 'build' + | 'cache' + | 'completion' + | 'config' + | 'deploy' + | 'doc' + | 'e2e' + | 'extract-i18n' + | 'generate' + | 'lint' + | 'make-this-awesome' + | 'new' + | 'run' + | 'serve' + | 'test' + | 'update' + | 'version'; + +export interface CommandConfig { + aliases?: string[]; + factory: () => Promise<{ default: CommandModuleConstructor }>; +} + +export const RootCommands: Record< + /* Command */ CommandNames & string, + /* Command Config */ CommandConfig +> = { + 'add': { + factory: () => import('./add/cli'), + }, + 'analytics': { + factory: () => import('./analytics/cli'), + }, + 'build': { + factory: () => import('./build/cli'), + aliases: ['b'], + }, + 'cache': { + factory: () => import('./cache/cli'), + }, + 'completion': { + factory: () => import('./completion/cli'), + }, + 'config': { + factory: () => import('./config/cli'), + }, + 'deploy': { + factory: () => import('./deploy/cli'), + }, + 'doc': { + factory: () => import('./doc/cli'), + aliases: ['d'], + }, + 'e2e': { + factory: () => import('./e2e/cli'), + aliases: ['e2e'], + }, + 'extract-i18n': { + factory: () => import('./extract-i18n/cli'), + }, + 'generate': { + factory: () => import('./generate/cli'), + aliases: ['g'], + }, + 'lint': { + factory: () => import('./lint/cli'), + }, + 'make-this-awesome': { + factory: () => import('./make-this-awesome/cli'), + }, + 'new': { + factory: () => import('./new/cli'), + aliases: ['n'], + }, + 'run': { + factory: () => import('./run/cli'), + }, + 'serve': { + factory: () => import('./serve/cli'), + aliases: ['s'], + }, + 'test': { + factory: () => import('./test/cli'), + aliases: ['t'], + }, + 'update': { + factory: () => import('./update/cli'), + }, + 'version': { + factory: () => import('./version/cli'), + aliases: ['v'], + }, +}; + +export const RootCommandsAliases = Object.values(RootCommands).reduce((prev, current) => { + current.aliases?.forEach((alias) => { + prev[alias] = current; + }); + + return prev; +}, {} as Record); diff --git a/packages/angular/cli/src/commands/completion/cli.ts b/packages/angular/cli/src/commands/completion/cli.ts index f6166c28b325..8c777a9b8d32 100644 --- a/packages/angular/cli/src/commands/completion/cli.ts +++ b/packages/angular/cli/src/commands/completion/cli.ts @@ -14,7 +14,10 @@ import { colors } from '../../utilities/color'; import { hasGlobalCliInstall, initializeAutocomplete } from '../../utilities/completion'; import { assertIsError } from '../../utilities/error'; -export class CompletionCommandModule extends CommandModule implements CommandModuleImplementation { +export default class CompletionCommandModule + extends CommandModule + implements CommandModuleImplementation +{ command = 'completion'; describe = 'Set up Angular CLI autocompletion for your terminal.'; longDescriptionPath = join(__dirname, 'long-description.md'); diff --git a/packages/angular/cli/src/commands/config/cli.ts b/packages/angular/cli/src/commands/config/cli.ts index 5977d8cfa02d..bb5cee4e66fd 100644 --- a/packages/angular/cli/src/commands/config/cli.ts +++ b/packages/angular/cli/src/commands/config/cli.ts @@ -25,7 +25,7 @@ interface ConfigCommandArgs { global?: boolean; } -export class ConfigCommandModule +export default class ConfigCommandModule extends CommandModule implements CommandModuleImplementation { diff --git a/packages/angular/cli/src/commands/deploy/cli.ts b/packages/angular/cli/src/commands/deploy/cli.ts index e335b0633e31..a4930680fc5e 100644 --- a/packages/angular/cli/src/commands/deploy/cli.ts +++ b/packages/angular/cli/src/commands/deploy/cli.ts @@ -11,7 +11,7 @@ import { MissingTargetChoice } from '../../command-builder/architect-base-comman import { ArchitectCommandModule } from '../../command-builder/architect-command-module'; import { CommandModuleImplementation } from '../../command-builder/command-module'; -export class DeployCommandModule +export default class DeployCommandModule extends ArchitectCommandModule implements CommandModuleImplementation { diff --git a/packages/angular/cli/src/commands/doc/cli.ts b/packages/angular/cli/src/commands/doc/cli.ts index 73b7826fc066..3f8a6e0e725c 100644 --- a/packages/angular/cli/src/commands/doc/cli.ts +++ b/packages/angular/cli/src/commands/doc/cli.ts @@ -13,6 +13,7 @@ import { CommandModuleImplementation, Options, } from '../../command-builder/command-module'; +import { RootCommands } from '../command-config'; interface DocCommandArgs { keyword: string; @@ -20,12 +21,12 @@ interface DocCommandArgs { version?: string; } -export class DocCommandModule +export default class DocCommandModule extends CommandModule implements CommandModuleImplementation { command = 'doc '; - aliases = ['d']; + aliases = RootCommands['doc'].aliases; describe = 'Opens the official Angular documentation (angular.io) in a browser, and searches for a given keyword.'; longDescriptionPath?: string; diff --git a/packages/angular/cli/src/commands/e2e/cli.ts b/packages/angular/cli/src/commands/e2e/cli.ts index 2aecfb3ac5a6..57cc6370618f 100644 --- a/packages/angular/cli/src/commands/e2e/cli.ts +++ b/packages/angular/cli/src/commands/e2e/cli.ts @@ -9,8 +9,9 @@ import { MissingTargetChoice } from '../../command-builder/architect-base-command-module'; import { ArchitectCommandModule } from '../../command-builder/architect-command-module'; import { CommandModuleImplementation } from '../../command-builder/command-module'; +import { RootCommands } from '../command-config'; -export class E2eCommandModule +export default class E2eCommandModule extends ArchitectCommandModule implements CommandModuleImplementation { @@ -31,7 +32,7 @@ export class E2eCommandModule multiTarget = true; command = 'e2e [project]'; - aliases = ['e']; + aliases = RootCommands['e2e'].aliases; describe = 'Builds and serves an Angular application, then runs end-to-end tests.'; longDescriptionPath?: string; } diff --git a/packages/angular/cli/src/commands/extract-i18n/cli.ts b/packages/angular/cli/src/commands/extract-i18n/cli.ts index 5283204f4e9b..a0d4bc366dfb 100644 --- a/packages/angular/cli/src/commands/extract-i18n/cli.ts +++ b/packages/angular/cli/src/commands/extract-i18n/cli.ts @@ -9,7 +9,7 @@ import { ArchitectCommandModule } from '../../command-builder/architect-command-module'; import { CommandModuleImplementation } from '../../command-builder/command-module'; -export class ExtractI18nCommandModule +export default class ExtractI18nCommandModule extends ArchitectCommandModule implements CommandModuleImplementation { diff --git a/packages/angular/cli/src/commands/generate/cli.ts b/packages/angular/cli/src/commands/generate/cli.ts index c4029e5a7e1f..424d609ed19a 100644 --- a/packages/angular/cli/src/commands/generate/cli.ts +++ b/packages/angular/cli/src/commands/generate/cli.ts @@ -25,17 +25,18 @@ import { } from '../../command-builder/schematics-command-module'; import { demandCommandFailureMessage } from '../../command-builder/utilities/command'; import { Option } from '../../command-builder/utilities/json-schema'; +import { RootCommands } from '../command-config'; interface GenerateCommandArgs extends SchematicsCommandArgs { schematic?: string; } -export class GenerateCommandModule +export default class GenerateCommandModule extends SchematicsCommandModule implements CommandModuleImplementation { command = 'generate'; - aliases = 'g'; + aliases = RootCommands['generate'].aliases; describe = 'Generates and/or modifies files based on a schematic.'; longDescriptionPath?: string | undefined; diff --git a/packages/angular/cli/src/commands/lint/cli.ts b/packages/angular/cli/src/commands/lint/cli.ts index bf145d31db0c..d6072d5549e6 100644 --- a/packages/angular/cli/src/commands/lint/cli.ts +++ b/packages/angular/cli/src/commands/lint/cli.ts @@ -11,7 +11,7 @@ import { MissingTargetChoice } from '../../command-builder/architect-base-comman import { ArchitectCommandModule } from '../../command-builder/architect-command-module'; import { CommandModuleImplementation } from '../../command-builder/command-module'; -export class LintCommandModule +export default class LintCommandModule extends ArchitectCommandModule implements CommandModuleImplementation { diff --git a/packages/angular/cli/src/commands/make-this-awesome/cli.ts b/packages/angular/cli/src/commands/make-this-awesome/cli.ts index fda66b295088..0c258a023f7b 100644 --- a/packages/angular/cli/src/commands/make-this-awesome/cli.ts +++ b/packages/angular/cli/src/commands/make-this-awesome/cli.ts @@ -10,7 +10,10 @@ import { Argv } from 'yargs'; import { CommandModule, CommandModuleImplementation } from '../../command-builder/command-module'; import { colors } from '../../utilities/color'; -export class AwesomeCommandModule extends CommandModule implements CommandModuleImplementation { +export default class AwesomeCommandModule + extends CommandModule + implements CommandModuleImplementation +{ command = 'make-this-awesome'; describe = false as const; deprecated = false; diff --git a/packages/angular/cli/src/commands/new/cli.ts b/packages/angular/cli/src/commands/new/cli.ts index c4f8bdebcece..202dd491bb3c 100644 --- a/packages/angular/cli/src/commands/new/cli.ts +++ b/packages/angular/cli/src/commands/new/cli.ts @@ -20,12 +20,13 @@ import { SchematicsCommandModule, } from '../../command-builder/schematics-command-module'; import { VERSION } from '../../utilities/version'; +import { RootCommands } from '../command-config'; interface NewCommandArgs extends SchematicsCommandArgs { collection?: string; } -export class NewCommandModule +export default class NewCommandModule extends SchematicsCommandModule implements CommandModuleImplementation { @@ -34,7 +35,7 @@ export class NewCommandModule protected override allowPrivateSchematics = true; command = 'new [name]'; - aliases = 'n'; + aliases = RootCommands['new'].aliases; describe = 'Creates a new Angular workspace.'; longDescriptionPath = join(__dirname, 'long-description.md'); diff --git a/packages/angular/cli/src/commands/run/cli.ts b/packages/angular/cli/src/commands/run/cli.ts index de7c185e9f3d..67d5c3a0f4b7 100644 --- a/packages/angular/cli/src/commands/run/cli.ts +++ b/packages/angular/cli/src/commands/run/cli.ts @@ -22,7 +22,7 @@ export interface RunCommandArgs { target: string; } -export class RunCommandModule +export default class RunCommandModule extends ArchitectBaseCommandModule implements CommandModuleImplementation { diff --git a/packages/angular/cli/src/commands/serve/cli.ts b/packages/angular/cli/src/commands/serve/cli.ts index 537345cc568d..48a1103355b2 100644 --- a/packages/angular/cli/src/commands/serve/cli.ts +++ b/packages/angular/cli/src/commands/serve/cli.ts @@ -8,14 +8,15 @@ import { ArchitectCommandModule } from '../../command-builder/architect-command-module'; import { CommandModuleImplementation } from '../../command-builder/command-module'; +import { RootCommands } from '../command-config'; -export class ServeCommandModule +export default class ServeCommandModule extends ArchitectCommandModule implements CommandModuleImplementation { multiTarget = false; command = 'serve [project]'; - aliases = ['s']; + aliases = RootCommands['serve'].aliases; describe = 'Builds and serves your application, rebuilding on file changes.'; longDescriptionPath?: string | undefined; } diff --git a/packages/angular/cli/src/commands/test/cli.ts b/packages/angular/cli/src/commands/test/cli.ts index fd650fee01c9..837d57787eb4 100644 --- a/packages/angular/cli/src/commands/test/cli.ts +++ b/packages/angular/cli/src/commands/test/cli.ts @@ -9,14 +9,15 @@ import { join } from 'path'; import { ArchitectCommandModule } from '../../command-builder/architect-command-module'; import { CommandModuleImplementation } from '../../command-builder/command-module'; +import { RootCommands } from '../command-config'; -export class TestCommandModule +export default class TestCommandModule extends ArchitectCommandModule implements CommandModuleImplementation { multiTarget = true; command = 'test [project]'; - aliases = ['t']; + aliases = RootCommands['test'].aliases; describe = 'Runs unit tests in a project.'; longDescriptionPath = join(__dirname, 'long-description.md'); } diff --git a/packages/angular/cli/src/commands/update/cli.ts b/packages/angular/cli/src/commands/update/cli.ts index c2c7ed05f58c..b691b02f0bb0 100644 --- a/packages/angular/cli/src/commands/update/cli.ts +++ b/packages/angular/cli/src/commands/update/cli.ts @@ -60,7 +60,7 @@ interface UpdateCommandArgs { const ANGULAR_PACKAGES_REGEXP = /^@(?:angular|nguniversal)\//; const UPDATE_SCHEMATIC_COLLECTION = path.join(__dirname, 'schematic/collection.json'); -export class UpdateCommandModule extends CommandModule { +export default class UpdateCommandModule extends CommandModule { override scope = CommandScope.In; protected override shouldReportAnalytics = false; diff --git a/packages/angular/cli/src/commands/version/cli.ts b/packages/angular/cli/src/commands/version/cli.ts index 863b9e2102f4..90dca4fbc271 100644 --- a/packages/angular/cli/src/commands/version/cli.ts +++ b/packages/angular/cli/src/commands/version/cli.ts @@ -11,6 +11,7 @@ import { resolve } from 'path'; import { Argv } from 'yargs'; import { CommandModule, CommandModuleImplementation } from '../../command-builder/command-module'; import { colors } from '../../utilities/color'; +import { RootCommands } from '../command-config'; interface PartialPackageInfo { name: string; @@ -37,9 +38,12 @@ const PACKAGE_PATTERNS = [ /^webpack$/, ]; -export class VersionCommandModule extends CommandModule implements CommandModuleImplementation { +export default class VersionCommandModule + extends CommandModule + implements CommandModuleImplementation +{ command = 'version'; - aliases = ['v']; + aliases = RootCommands['version'].aliases; describe = 'Outputs Angular CLI version.'; longDescriptionPath?: string | undefined;