【前端脚手架开发】第二节-认识commander

107 阅读5分钟

commander 是node.js命令行接口的完整解决方案。

  • 创建命令及配置参数
  • 显示使用错误
  • 可以提供帮助提示

安装(这里以@11.0.0版本为例)

npm install commander@11.0.0 -S

导入方式

const { program } = require("commander"); // program 是 Command的一个实例
// 或者 两种方式本质上是一样
// const { Command } = require('commander');
// const program = new Command();

version 方法定义要开发的程序的版本号,接收三个参数

  1. 类型[string] 必填参数,版本号,例:1.0.0
  2. 类型[string] 可选参数,自定义选项名称,默认 -V(短命令) | --version(长命令) , 命令之间可以用逗号空格|分割,且短名称和长名称都最多只能有一个
  3. 类型[string] 可选参数,命令描述
const { program } = require("commander");
program.version("0.1.0", "-v|--version", "版本号");
program.parse(process.argv); // 此行代码控制终端是否展示命令结果

重要方法option,接收以下参数

  1. 类型[string] 必填参数,自定义选项名称, -f(短命令) | --feer(长命令) , 命令之间可以用逗号空格|分割,且短名称和长名称都最多只能有一个
  2. 类型[string] 可选参数,选项描述
  3. 类型[((v,prev) => v)|string|boolean|string[]] 可选参数,如果传入的是函数,则可以通过函数修改返回值,如果不是函数则当默认值处理
  4. 类型[string|boolean|string[]] 当且仅当 3 是函数时,此参数有意义且是默认值

option 接收4个参数时

  1. 选项有必填参数时
const { program } = require("commander");
/*option 定义选项 
  参数1. (-t, --test) (-t|--test) (-t --test) 三种写法都可以,定义选项短(长)命名
  参数1. <n> 选项参数,可不定义 (<>是必填,[]是可选,[a...]是多个可选参数) 
  参数2. “测试” 针对该选项的描述
  参数3. (v, prev) => v + "-" + prev  修改返回结果
  参数4. "12" 默认值
*/
program
  .option("-t, --test <n>", "测试", (v, prev) => v + "-" + prev, "12")
  .action((p) => {
    console.log("拿到的参数为:", p);
    // 输入33, 得到结果 { test: '33-12' }
  });
  1. 选项有可选参数时
const { program } = require("commander");
program.option("-t, --test [m]", "测试", 321).action((v) => {
  // 执行 node ./program.js
  console.log("得到结果:", v, "默认值:", program.opts().test);
  // 得到结果: { test: 321 } 默认值: 321  未传入选项参数,则拿到默认值
  /* 执行 node ./program.js -t 00
    console.log("得到结果:", v, "默认值:", program.opts().test);
    得到结果:{ test: '00' } 默认值: 00 传入00 则会覆盖默认值
  */
});

option 接收3个参数时

const { program } = require("commander");
/*option 定义选项
  参数1/2 和上面一样
  参数3. "12" 默认值
*/
program.option("-a, --add <n>", "测试", "12").action((p) => {
  console.log("拿到的参数为:", p);
  // 输入33, 得到结果 { add: '33' }
});

addOption 该方法传入一个Option实例,可以定义一些复杂的选项(option方法不能满足)

1.choices用法,程序会自动检测输入选项是否存在,不存在则报错(程序自动检测选项参数合法性)

const { program, Option } = require("commander");
// 接收一个参数 Option 类
program
  .addOption(
    new Option("-s, -save <size>", "尺寸").choices(["small", "normal", "large"])
  )
  .action((v) => {
    // 错误示范 node ./addOption.js -s 12  输入的是非"small", "normal", "large"时 报错“error: option '-s, -save <size>' argument '12' is invalid. Allowed choices are small, normal, large.”
    // 正确 node ./addOption.js -s large  得到参数 { Save: 'large' }
    console.log("得到参数", v);
  })
  .parse();

2.默认值用法,设置默认值时如果要得到默认值,执行命令时均不带选项名称

const { program, Option } = require("commander");

// 接收一个参数 Option 类
program
  .addOption(
    new Option("-s, --save [size]", "尺寸") // 选项参数改为了可选
      .choices(["small", "normal", "large"])
      .default("small") // 默认值设置
  )
  .action((v) => {
    // node ./addOption.js 不带选项名称时 得到参数 { save: 'small' }{ save: 'small' }
    console.log("得到参数", v, program.opts());
  })
  .parse();

3.其他用法

program
  .addOption(new Option("-s, --secret").hideHelp()) // 帮助提示隐藏该选项
  .addOption(
    new Option("-t, --timeout <delay>", "timeout in seconds").default(
      60,
      "one minute"
    ) // 设置默认值
  )
  .addOption(
    new Option("-d, --drink <size>", "drink size").choices([
      "small",
      "medium",
      "large",
    ]) // 定义选项范围
  )
  .addOption(new Option("-p, --port <number>", "port number").env("PORT"))
  .addOption(
    new Option("--donate [amount]", "optional donation in dollars")
      .preset("20")
      .argParser(parseFloat) // 对输入结果做解析格式化操作
  )
  .addOption(
    new Option("--disable-server", "disables the server").conflicts("port")
     // 和选项port 互斥,不能连用如:node ./addOption.js --disable-server -p 30
  )
  .addOption(
    new Option("--free", "small drink included free ").implies({
      drink: "12",
    }) // 添加额外选项参数值
  )
  .action((v) => {
    console.log(v);
  })
  .parse();

command 创建命令, 接收两个参数

  1. 第一个参数和option类似(命令不需要加-和--)
  2. 第二参数是对象 {hidden:帮助提示时是否隐藏该命令,isDefault:是否是默认命令}
const { program } = require("commander");
/** 创建一个clone命令,该命令用一个必填参数,一个可选参数 */
program
  .command("clone <source> [destination]")
  .description("clone a repository into a newly created directory")
  .action((source, destination) => {
    console.log("得到参数", source, destination);
    // 执行 node ./command.js clone 12 得到参数 clone 12
  })
  .parse();

argument 定义参数的方法

  1. 类型[string] 必填参数,定义可选[]、必填<>
  2. 类型[string] 可选参数,定义的参数的描述
  3. 类型[((v,prev) => v)|string|boolean|string[]] 可选参数,如果传入的是函数,则可以通过函数修改返回值,如果不是函数则当默认值处理
  4. 类型[string|boolean|string[]] 当且仅当 3 是函数时,此参数有意义且是默认值
const { program } = require("commander");
program
  .version("0.1.0")
  .argument("<username>", "user to login")
  .argument("[password]", "password for user, if required", 123456)
  .action((username, password) => {
    console.log("username:", username);
    console.log("password:", password);
    // 执行node ./argument.js name, 得到结果 username: name password: 123456
  })
  .parse();

以上就是一些关键的函数,接下来列举些案例

  1. 模拟 git clone 命令, 添加选项 -b 未输入时默认是 master
const { program } = require("commander");
program
  .command("clone")
  .argument("<source>", "远程仓库地址")
  .option("-b, --branch", "指定分支", "master")
  .action((p, b) => {
    console.log("拿到参数:", p, b);
    // 执行 node ./demo.js clone https://githup*** -b dev
    // 终端打印:拿到参数: https://githup*** { branch: true }
  });
  program.parse();
  1. 模拟 npm 安装依赖命令
const { program } = require("commander");
program
  .command("i")
  .description("安装依赖")
  .argument("<name>", "依赖名称")
  .option("-dev, --devloop", "安装到开发依赖")
  .option("-prod, --production", "安装到生产依赖")
  .action((p1, p2) => {
    console.log("得到参数", { p1, p2 });
    // 执行 node ./demo.js i dayjs -dev
    // 终端打印:得到参数 { p1: 'dayjs', p2: { devloop: true } }
  });
program
  .command("install")
  .description("安装依赖")
  .argument("<name>", "依赖名称")
  .option("-dev, --devloop", "安装到开发依赖")
  .option("-prod, --production", "安装到生产依赖")
  .action((p1, p2) => {
    console.log("得到参数", { p1, p2 });
    // 执行 node ./demo.js install dayjs -dev
    // 终端打印:得到参数 { p1: 'dayjs', p2: { devloop: true } }
  });
program.parse();

以上就是本节主要内容,由于技术有限,见解较浅,希望各路大神多多指导

以上案例代码如有需要,可克隆本地运行

git clone https://gitee.com/luocheng-fu/commander-demo.git