yargs脚手架命令注册

826 阅读1分钟
  • 查看lerna源码用的就是yargs的库注册脚手架,@vue/cli是自己开发的
  • command 命令注册
  • options 参数注册
  • 常用方法

image.png

#!/usr/bin/env node

const yargs = require("yargs/yargs");
const dedent = require("dedent");
// 使用了.parse(argv, context)就不需要传argv了
// const { hideBin } = require("yargs/helpers");
const pkg = require('../package.json');
const cli = yargs()
const ListCmd = require('./command/list')

 const context = {
   rainbowVersion: pkg.version,
 };

 const argv = process.argv.slice(2)

  // dedent去除缩进
  cli
  // 未知命令的提示
    // .strict()
    // $0 值为argv第一个参数
    .usage("Usage: $0 <command> [options]")
    .demandCommand(
      1,
      "A command is required. Pass --help to see all available commands and options."
    )
    // 如果命令输入错误,会提示
    .recommendCommands()
    .alias("h", "help")
    .alias("v", "version")
    // 定义多个option参数
    .options({
      debugger: {
        defaultDescription: "",
        describe: "bootstrap debugger mode",
        type: "boolean",
        alias: "d",
      },
    })
    // 注册单个option参数
    .option("register", {
      describe: "Define Global Option",
      type: "string",
      alias: "r",
    })
    .option("ci", {
      type: "boolean",
      hidden: true,
    })
    // 定义命令分组
    .group(["debugger"], "Dev Options")
    .group(["register"], "Extra Options")
    // 当输入错误命令的时候的提示内容
    .fail((err,msg) => {
      /* 此时会把命令中相近的进行提示
        是指 init?
        无法识别的选项:iii
      */
      console.log(err);
    })
    // 自定义yargs命令,有四个参数
    // 可以使用rainbow-test init -h查看帮助文档
    .command(
      "[init [name]]",
      "Do init a project",
      (yargs) => {
        yargs.option("name", {
          type: "string",
          describe: "Name of a Project",
          alias: "n",
        });
      },
      (argv) => {
        console.log(argv); //查看参数
        /* 
      {
        _: [ 'init' ],
        rainbowVersion: '1.1.0',
        '$0': '/usr/local/bin/rainbow-test'
      } 
    */
      }
    )
    // Lerna源码使用的就是这种方式,但是yargs帮助文档并没有介绍
    .command(ListCmd)
    .command({
      command: "test",
      aliases: ["t", "te", "tes"],
      describe: "test local packages",
      // 在执行脚手架之前完成的东西 ,比如定义私有的options   
      builder: (yargs) => {
        console.log("test the command");
      },
      // 具体执行逻辑
      handler: function handler(argv) {
        //   return require(".")(argv);
        console.log(argv);
        return {
          initialize() {
            console.log("initialize");
          },
          execute() {
            // piping to `wc -l` should not yield 1 when no packages matched
           console.log("execute");
          },
        };
      },
    })
    .command({
      command:"start",
      alias:['s'],
      describe:"start the project",
      builder:(yargs)=>{
        console.log('');
      },
      handler:(argv)=>{
        console.log(argv);
        console.log('start');
        setTimeout(()=>{
          console.log('setTimeout');
        },0);
        new Promise(()=>{
          let chain = Promise.resolve();
          chain.then(() => console.log("chain1"))
          chain.then(() => console.log("chain2"))
          chain.then(() => console.log("chain3"));
        })

        let chain = Promise.resolve();
        chain.then(() => console.log("chain4"));
        setTimeout(()=>{
          console.log('setTimeout2');
        },0)
        console.log("end");

      }
    })
    // 设置输出的宽度
    .wrap(cli.terminalWidth())
    // 结尾的时候定义内容
    .epilogue(
      dedent` 
       When a command fails, all logs are written to lerna-debug.log in the current working directory.

      For more information, find our manual at https://github.com/lerna/lerna
    `
      // 注入参数,比如注册版本号
    )
    .parse(argv, context);

commander命令注册

#!/usr/bin/env node

const { program } = require("commander");
program.version("0.0.1").parse(process.argv);

默认就由-h-V的命令注册 image.png

image.png

注册子命令 image.png

#!/usr/bin/env node

const { Command } = require("commander");
const pkg = require("../package.json");
// 实例化一个commander实例
const program = new Command();
const options = program.opts();

program
  .name(Object.keys(pkg.bin)[0])
  .usage(`<command> [options]`)
  .version(pkg.version)
  .option("-d, --debug", "是否开启调试模式", false) // -d, --debug 是否开启调试模式 (default: false)
  .option("-e, --envName <envName>", "获取环境变量")
  
// command注册命令
const clone = program.command("clone <source> [destination]"); //<>表示必须传入 []为可选
clone
  .description("clone a reposity")
  .option("-f, --force", "是否开启调试模式", false)
  .action((source, destination,Optionsobj) => {
    console.log("this is clone command", source, destination);
  });
/*
rainbow-test clone 12 14 --force
// this is clone command 12 14 { force: true }
rainbow-test clone --force 12 14 
// this is clone command 12 14 { force: true }
rainbow-test clone --force 12 14 --o
// error: unknown option '--o'
不管--force在哪里都可以被识别
*/

/***
 * addCommand注册一个service子命令
 * rainbow-test service -h
 */
const service = new Command('service')
service
  .command("start <port>")
  .description("start service at some port")
  .action((port) => {
    console.log("do service start", port);
  });
service
  .command("stop")
  .description("stop service")
  .action(() => {
    console.log("stop service");
  });
program.addCommand(service); // 完成子命令注册


/**
 * 注册rainbow-test-install
 */
program
  .command("install [name]", "install package", {
    executableFile: "rainbow-cli", //更换执行命令
    // isDefault:true, //如果没有输入任何命令,则使用默认命令
    hidden:true //隐藏帮助文档中的command
    //Error: 'rainbow-install' does not exist
    //如果换成已经有的脚手架命令也可以使用
  }) //Error: 'rainbow-test-install' does not exist
  .alias("i") //install|i [name]  install package
  

/**
 * Yargs.demandCommand
 * rainbow-test 如果不传入命令, 报错:error: missing required argument 'cmd'
 * 如果是未知命令也可以监听到
 */
// program
//   .arguments("<cmd> [options]") //Usage下面的命令解释,如果输入未知的命令,怎会提示
//   .description("test command", {
//     cmd: "command to run",
//     options: "options to command",
//   })
//   .action((cmd, options) => {
//     console.log("arguments", cmd, options);
//   });

  /**
   * 高级定制1: 自定义help信息
   */
program.helpInformation = ()=>{ return ''} 
program.on("--help", function() {
  console.log("youer help infomation\n");
});

// 高级定制:实现debug模式,取代minimist
program.on("option:debug", function() {
  if (options.debug) {
    process.env.LOG_LEVEL = "verbose";
  }
  console.log(process.env.LOG_LEVEL);
});

// 高级定制:对未知命令监听
program.on("command:*", function(operands) {
  console.error(`error: unknown command '${operands[0]}'`);
  const availableCommands = program.commands.map(cmd => cmd.name());
  console.log(`可用命令:${availableCommands.join(",")}`);
  process.exitCode = 1;
});

// 必须放 在最后面解析参数
program.parse(process.argv);

program.on()命令监听,自定义输出 image.png