Browse Source

perf(cli): Lazy load commands to improve startup time

Makes add/help command about 2 seconds faster to run
Michael Bromley 1 year ago
parent
commit
ec2f497420

+ 17 - 5
packages/cli/src/cli.ts

@@ -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
@@ -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);

+ 48 - 55
packages/cli/src/commands/add/add.ts

@@ -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';
@@ -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');
+    }
 }

+ 35 - 42
packages/cli/src/commands/migrate/migrate.ts

@@ -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';
@@ -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);
+        }
+    }
 }