想阅读vue-cli源码,commander你都不会吗?

243 阅读3分钟

一、概述

在当前我们前端项目中,大多数情况下,都是使用对应框架开发的脚手架进行项目工程化的搭建,既然要用到脚手架,那么肯定会用到命令,比如vue-cli的创建命令:vue init webpack projeckName,要想解析控制台输出的自定义命令,离不开commander这个工具。

commander是一个轻巧的nodejs模块,提供了用户命令行输入和参数解析强大功能

二、使用

1. 搭建项目

npm init -y gnip  // 名字可以随便起,但是不要和包名重复,不然导致包无法下载

新建 bin/index 目录
以下文件在该目录下写
#!/usr/bin/env node   // 可以设置成全局命令
//下面正常的node代码,比如我们需要配置的命令
console.log('自定义命令执行了")
{
  "name": "gnip",  //项目名字
  "version": "1.0.4", // 版本
  "description": "gnip-cli", // 介绍
  "main": "index.js",
  //这里将我们全局需要执行的命令放到这里,当我们npm下载时候,会自动加到环境变量中(然后你就可以通过 gnip xxx使用你的命令了)
  "bin": {
    "gnip": "./index.js"
  },
  "scripts": {},
  "keywords": [
    "cli"
  ],
  "author": "gnip",
  "license": "ISC",
  "devDependencies": {
    "commander": "^9.4.0",
    "download-git-repo": "^3.0.2"
  },
  "dependencies": {
    "ejs": "^3.1.8",
    "inquirer": "^7.3.3"
  },
  "files": [
    "node_modules",
    "lib",
    "*"
  ]
}

执行npm link,将当前项目映射到全局,在其他目录下我们就可以使用gnip这个全局命令了

2. 核心命令

2.1 parse()

parse的第一个参数是要解析的字符串数组,也可以省略参数而使用process.argv

如果参数遵循与 node 不同的约定,可以在第二个参数中传递from选项:

  • node :默认值, argv[0] 是应用, argv[1] 是要跑的脚本,后续为用户参数;
  • electron argv[1] 根据 electron 应用是否打包而变化;
  • user :来自用户的所有参数。
// 在执行相关的命令后,要在控制台打印相关的信息的话,必须在最后执行以下代码
program.parse(process.argv); // 指明,按 node 约定
program.parse(); // 默认,自动识别 electron
program.parse(['-f', 'filename'], { from: 'user' });

2.2 version

这个方法可以用来输出当前你的脚手架工具的版本号。

参数:

  • 版本号,必须参数
  • 自定义命令标识,可选参数,默认为-V--version
  • 描述信息,可选参数
#!/usr/bin/env node
const program = require('commander');

// 只有版本信息
program.version('0.0.1');
program.parse();

// 自定义命令标识
// 添加了自定义参数后,执行命令就可以使用自己定义的参数了
program.version('1.0.0', '-v, --vers');
program.parse();

2.3 options

这个方法可以使我们执行类似于gnip -g haha 等的带参数的命令时,可以解析注意点:

  • 每个选项可以定义一个短选项名称(-后面接单个字符)和一个长选项名称(--后面接一个或多个单词),使用逗号、空格或 | 分隔。
  • 这种<>尖角括号代表必填参数(后面不跟参数会提示少参数)
  • 这种[]中括号代表可填参数
#!/usr/bin/env node
const program = require("commander");
program.option('-j | --join','Join IMWeb now!')

program.parse()

// 解析后的选项可以通过Command对象上的.opts()方法获取,同时会被传递给命令处理函数。可以使用.getOptionValue()和.setOptionValue()操作单个选项的值。
console.log(program.opts()) // {join: true}
console.log(program.getOptionValue('join')) // true

带参数

#!/usr/bin/env node
const program = require("commander");
program
  .version('1.1.0')
  .option('-a, --argu-test <name>', 'test option function -- agru test','我是默认参数') 
// 带参数<>,   option第三个参数为默认参数
program.parse()

// tip
1. 如果写了<>并且没有默认参数,使用 gnip index -a  报错没有参数
2. 如果写了<>并且没有默认参数,使用 gnip index -a name  参数则为name
3. 如果写了<>并且有默认参数,使用 gnip index   参数则为option的默认参数
4. 如果写了<>并且有默认参数,使用 gnip index -a name   参数则为name

取反值

// 可以定义一个以no-开头的 boolean 型长选项。在命令行中使用该选项时,会将对应选项的值置为false。当只定义了带no-的选项,未定义对应不带no-的选项时,该选项的默认值会被置为true。
const program = require('commander');
program.option('--no-cheese', 'plain with no cheese');
program.parse();
console.log(program.opts());  // {cheese: false}

2.4 command

.command()的第一个参数为命令名称。命令参数可以跟在名称后面,也可以用.argument()单独指定。参数可为必选的(尖括号表示)、可选的(方括号表示)或变长参数(点号表示,如果使用,只能是最后一个参数)。

帮助信息是 Commander 基于你的程序自动生成的,默认的帮助选项是-h,--help。

第一种写法

program
.command('clone <source> [destination]')
// description:用来描述命令的一些提示、说明性的语句,我们在使用help命令时会打印出这些相关的描述
.description('clone a repository into a newly created directory')
// action: 自定义命令执行后的回调函数。
.action((source, destination) => {
    console.log('source', source)
    console.log('destination', destination)
    console.log('called')
});

command另一种用法

使用格式  .command('add  [params]', 'install description', opts)

第二个参数是描述
第三个参数是命令辅助修饰对象(可选)
当 .command() 带有描述参数时,不能采用 .action(callback) 来处理子命令,否则会出错,这告诉 commander,你将采用单独的可执行文件作为子命令。

例如:
program
  .command("init", "generate a new project from a template")
  .command("list", "list available official templates")
  .command("build", "prototype a new project")
  .command("create", "(for v3 warning only)");
program.parse()

参考文章

commander脚手架工具使用详解
github-commander.js