I would like to follow up on my previous post about TypeScript CLIs. Here's how I want to proceed: I plan to implement the build command to build a Vite app and the deploy command to deploy the app to Amazon S3 and AWS CloudFront.
We will use Listr2 as a task runner to define the steps required to build and deploy the app. We will use execa to run CLI commands for Vite and AWS. Since we're running TypeScript code, we could use the programmatic APIs instead of CLI commands, but let's keep it simple!
#!/usr/bin/env -S pnpm tsx import chalk from 'chalk'; import { Command } from 'commander'; import { Listr } from 'listr2'; import { $ } from 'execa'; interface Ctx { command: 'build' | 'deploy'; } const tasks = new Listr<ctx>( [ /** * Build tasks */ { enabled: (ctx) => ctx.command === 'build' || ctx.command === 'deploy', title: 'Build', task: (ctx, task): Listr => task.newListr<ctx>([ /** * Runs `vite build`. */ { title: `Run ${chalk.magenta('vite build')}`, task: async (ctx, task): Promise<void> => { const cmd = $({ all: true })`vite build`; cmd.all.pipe(task.stdout()); await cmd; task.output = `Build completed: ${chalk.dim('./dist')}`; }, rendererOptions: { persistentOutput: true }, }, ]), }, /** * Deploy tasks */ { enabled: (ctx) => ctx.command === 'deploy', title: 'Deploy', task: (ctx, task): Listr => task.newListr<ctx>([ /** * Runs `aws s3 sync`. */ { title: `Run ${chalk.magenta('aws s3 sync')}`, task: async (ctx, task): Promise<void> => { const build = './dist'; const bucket = 's3://my-bucket'; const cmd = $({ all: true })`aws s3 sync ${build} ${bucket} --delete`; cmd.all.pipe(task.stdout()); await cmd; task.output = `S3 sync completed: ${chalk.dim(bucket)}`; }, rendererOptions: { persistentOutput: true }, }, /** * Runs `aws cloudfront create-invalidation`. */ { title: `Run ${chalk.magenta('aws cloudfront create-invalidation')}`, task: async (ctx, task): Promise<void> => { const distributionId = 'E1234567890ABC'; const cmd = $({ all: true })`aws cloudfront create-invalidation --distribution-id ${distributionId} --paths /* --no-cli-pager`; cmd.all.pipe(task.stdout()); await cmd; task.output = `CloudFront invalidation completed: ${chalk.dim(distributionId)}`; }, rendererOptions: { persistentOutput: true }, }, ]), }, ], { rendererOptions: { collapseSubtasks: false, }, }, ); const program = new Command() .name('monorepo') .description('CLI for Monorepo') .version('1.0.0'); program .command('build') .description('Build the monorepo') .action(async () => { await tasks.run({ command: 'build' }); }); program .command('deploy') .description('Deploy the monorepo') .action(async () => { await tasks.run({ command: 'deploy' }); }); await program.parseAsync(process.argv); </void></void></ctx></void></ctx></ctx>
The tasks are split into build tasks and deploy tasks. Since deploying requires a build step, we use the enabled property to conditionally enable the tasks based on the CLI command build or deploy. Each task executes the corresponding CLI command and pipes its output to the console.
Save this script as cli.ts and run it with pnpm tsx cli:
The above is the detailed content of TypeScript CLI: Automate Build and Deploy Scripts. For more information, please follow other related articles on the PHP Chinese website!