Skip to content

Commit

Permalink
perf(cli): Lazy load commands to improve startup time
Browse files Browse the repository at this point in the history
Makes add/help command about 2 seconds faster to run
  • Loading branch information
michaelbromley committed Apr 9, 2024
1 parent 9818b7c commit ec2f497
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 102 deletions.
22 changes: 17 additions & 5 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
import { Command } from 'commander';
import pc from 'picocolors';

import { registerAddCommand } from './commands/add/add';
import { registerMigrateCommand } from './commands/migrate/migrate';

const program = new Command();

// eslint-disable-next-line @typescript-eslint/no-var-requires
Expand All @@ -27,7 +24,22 @@ Y88 88P 88888888 888 888 888 888 888 888 888 88888888
`),
);

registerAddCommand(program);
registerMigrateCommand(program);
program
.command('add')
.description('Add a feature to your Vendure project')
.action(async () => {
const { addCommand } = await import('./commands/add/add');
await addCommand();
process.exit(0);
});

program
.command('migrate')
.description('Generate, run or revert a database migration')
.action(async () => {
const { migrateCommand } = await import('./commands/migrate/migrate');
await migrateCommand();
process.exit(0);
});

void program.parseAsync(process.argv);
103 changes: 48 additions & 55 deletions packages/cli/src/commands/add/add.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { cancel, intro, isCancel, log, outro, select, spinner } from '@clack/prompts';
import { Command } from 'commander';
import pc from 'picocolors';

import { Messages } from '../../constants';
Expand All @@ -16,60 +15,54 @@ import { addUiExtensionsCommand } from './ui-extensions/add-ui-extensions';

const cancelledMessage = 'Add feature cancelled.';

export function registerAddCommand(program: Command) {
program
.command('add')
.description('Add a feature to your Vendure project')
.action(async () => {
// eslint-disable-next-line no-console
console.log(`\n`);
intro(pc.blue("✨ Let's add a new feature to your Vendure project!"));
const addCommands: Array<CliCommand<any>> = [
createNewPluginCommand,
addEntityCommand,
addServiceCommand,
addApiExtensionCommand,
addJobQueueCommand,
addUiExtensionsCommand,
addCodegenCommand,
];
const featureType = await select({
message: 'Which feature would you like to add?',
options: addCommands.map(c => ({
value: c.id,
label: `[${c.category}] ${c.description}`,
})),
});
if (isCancel(featureType)) {
cancel(cancelledMessage);
process.exit(0);
}
try {
const command = addCommands.find(c => c.id === featureType);
if (!command) {
throw new Error(`Could not find command with id "${featureType as string}"`);
}
const { modifiedSourceFiles, project } = await command.run();
export async function addCommand() {
// eslint-disable-next-line no-console
console.log(`\n`);
intro(pc.blue("✨ Let's add a new feature to your Vendure project!"));
const addCommands: Array<CliCommand<any>> = [
createNewPluginCommand,
addEntityCommand,
addServiceCommand,
addApiExtensionCommand,
addJobQueueCommand,
addUiExtensionsCommand,
addCodegenCommand,
];
const featureType = await select({
message: 'Which feature would you like to add?',
options: addCommands.map(c => ({
value: c.id,
label: `[${c.category}] ${c.description}`,
})),
});
if (isCancel(featureType)) {
cancel(cancelledMessage);
process.exit(0);
}
try {
const command = addCommands.find(c => c.id === featureType);
if (!command) {
throw new Error(`Could not find command with id "${featureType as string}"`);
}
const { modifiedSourceFiles, project } = await command.run();

if (modifiedSourceFiles.length) {
const importsSpinner = spinner();
importsSpinner.start('Organizing imports...');
await pauseForPromptDisplay();
for (const sourceFile of modifiedSourceFiles) {
sourceFile.organizeImports();
}
await project.save();
importsSpinner.stop('Imports organized');
}
outro('✅ Done!');
} catch (e: any) {
log.error(e.message as string);
const isCliMessage = Object.values(Messages).includes(e.message);
if (!isCliMessage && e.stack) {
log.error(e.stack);
}
outro('❌ Error');
if (modifiedSourceFiles.length) {
const importsSpinner = spinner();
importsSpinner.start('Organizing imports...');
await pauseForPromptDisplay();
for (const sourceFile of modifiedSourceFiles) {
sourceFile.organizeImports();
}
process.exit(0);
});
await project.save();
importsSpinner.stop('Imports organized');
}
outro('✅ Done!');
} catch (e: any) {
log.error(e.message as string);
const isCliMessage = Object.values(Messages).includes(e.message);
if (!isCliMessage && e.stack) {
log.error(e.stack);
}
outro('❌ Error');
}
}
77 changes: 35 additions & 42 deletions packages/cli/src/commands/migrate/migrate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { cancel, intro, isCancel, log, outro, select } from '@clack/prompts';
import { Command } from 'commander';
import pc from 'picocolors';

import { generateMigrationCommand } from './generate-migration/generate-migration';
Expand All @@ -13,45 +12,39 @@ const cancelledMessage = 'Migrate cancelled.';
* peculiarities in loading ESM modules vs CommonJS modules. More time is needed to dig into
* this before we expose this command in the cli.ts file.
*/
export function registerMigrateCommand(program: Command) {
program
.command('migrate')
.description('Generate, run or revert a database migration')
.action(async () => {
// eslint-disable-next-line no-console
console.log(`\n`);
intro(pc.blue('🛠️️ Vendure migrations'));
const action = await select({
message: 'What would you like to do?',
options: [
{ value: 'generate', label: 'Generate a new migration' },
{ value: 'run', label: 'Run pending migrations' },
{ value: 'revert', label: 'Revert the last migration' },
],
});
if (isCancel(action)) {
cancel(cancelledMessage);
process.exit(0);
}
try {
process.env.VENDURE_RUNNING_IN_CLI = 'true';
if (action === 'generate') {
await generateMigrationCommand.run();
}
if (action === 'run') {
await runMigrationCommand.run();
}
if (action === 'revert') {
await revertMigrationCommand.run();
}
outro('✅ Done!');
process.env.VENDURE_RUNNING_IN_CLI = undefined;
} catch (e: any) {
log.error(e.message as string);
if (e.stack) {
log.error(e.stack);
}
}
process.exit(0);
});
export async function migrateCommand() {
// eslint-disable-next-line no-console
console.log(`\n`);
intro(pc.blue('🛠️️ Vendure migrations'));
const action = await select({
message: 'What would you like to do?',
options: [
{ value: 'generate', label: 'Generate a new migration' },
{ value: 'run', label: 'Run pending migrations' },
{ value: 'revert', label: 'Revert the last migration' },
],
});
if (isCancel(action)) {
cancel(cancelledMessage);
process.exit(0);
}
try {
process.env.VENDURE_RUNNING_IN_CLI = 'true';
if (action === 'generate') {
await generateMigrationCommand.run();
}
if (action === 'run') {
await runMigrationCommand.run();
}
if (action === 'revert') {
await revertMigrationCommand.run();
}
outro('✅ Done!');
process.env.VENDURE_RUNNING_IN_CLI = undefined;
} catch (e: any) {
log.error(e.message as string);
if (e.stack) {
log.error(e.stack);
}
}
}

0 comments on commit ec2f497

Please sign in to comment.