Metadata

:LiFlag: 文档状态:YCDONE

:LiCalendarDays: 创建日期:2025-03-03

:LiTags: 标签列表:#实践,记录,前端工程化

:LiKeyRound:: 关键词列表:inquirer,command,chalk

核心功能

命令行美化

  • chalk
  • ora

命令行参数解析

  • command

项目模板生成

  • fs.readdirSync
  • fs.mkdirSync
  • fs.copyFileSync

交互式命令

  • inquirer

基本逻辑

#!/usr/bin/env node
 
import { Command } from 'commander';
import chalk from 'chalk';
import inquirer from 'inquirer';
import * as fs from 'fs';
import * as path from 'path';
import * as pkg from '../package.json';
import ora from 'ora';
 
const program = new Command();
 
// 设置CLI基本信息
program
  .name('demo')
  .description('一个功能完善的CLI工具')
  .version(pkg.version);
 
// 添加new命令用于创建新项目
program
  .command('new')
  .description('创建一个新项目')
  .argument('<name>', '项目名称')
  .option('-t, --template <template>', '项目模板')
  .action(async (name, options) => {
    const templates = ['react', 'vue', 'node'];
    let template = options.template;
 
    if (!template) {
      const answer = await inquirer.prompt([
        {
          type: 'list',
          name: 'template',
          message: '请选择项目模板:',
          choices: templates
        }
      ]);
      template = answer.template;
    }
 
    if (!templates.includes(template)) {
      console.log(chalk.red(`错误:不支持的模板类型 ${template}`));
      return;
    }
 
    const spinner = ora('正在创建项目...').start();
 
    try {
      const templatePath = path.join(__dirname, '..', 'templates', template);
      const targetPath = path.join(process.cwd(), name);
 
      // 创建目标目录
      if (!fs.existsSync(targetPath)) {
        fs.mkdirSync(targetPath, { recursive: true });
      }
 
      // 复制模板文件
      const copyFiles = (source: string, target: string) => {
        const files = fs.readdirSync(source);
        files.forEach(file => {
          const sourcePath = path.join(source, file);
          const targetPath = path.join(target, file);
 
          if (fs.statSync(sourcePath).isDirectory()) {
            fs.mkdirSync(targetPath, { recursive: true });
            copyFiles(sourcePath, targetPath);
          } else {
            fs.copyFileSync(sourcePath, targetPath);
          }
        });
      };
 
      copyFiles(templatePath, targetPath);
 
      // 更新package.json
      const packageJsonPath = path.join(targetPath, 'package.json');
      if (fs.existsSync(packageJsonPath)) {
        const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
        packageJson.name = name;
        fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
      }
 
      spinner.succeed(chalk.green(`项目 ${name} 创建成功!`));
      console.log(chalk.blue('\n开始使用:'));
      console.log(`  cd ${name}`);
      console.log('  npm install');
      console.log('  npm start\n');
    } catch (error) {
      spinner.fail(chalk.red('项目创建失败:' + error));
    }
  });
 
// 添加serve命令用于启动开发服务器
program
  .command('serve')
  .description('启动开发服务器')
  .option('-p, --port <port>', '端口号', '4200')
  .action((options) => {
    console.log(chalk.blue(`启动开发服务器在端口: ${options.port}`));
  });
 
// 添加build命令用于构建项目
program
  .command('build')
  .description('构建项目')
  .option('--prod', '生产环境构建')
  .action((options) => {
    console.log(chalk.blue(`构建项目${options.prod ? '(生产环境)' : ''}`));
  });
 
// 解析命令行参数
program.parse(process.argv);

demo 地址