commander
1 )概述
- commander 是一个更为知名的脚手架框架
- 进入它的npm官网: https://www.npmjs.com/package/commander
- 目前版本: 12.0.0
- Weekly Downloads 133,822,797 (动态数据)
- 最近更新:15 days ago (npm)
- 说明这是一个更优质的库
- 同时使用commander的案例也更为知名:vue-cli,webpack-cli,create-react-app
- 所以commander是我们开发脚手架过程中首选的框架
2 )快速实现一个 commander 脚手架
- 仍旧在 xyzcli 这个脚手架项目之下,之前是使用 yargs, 这时候把 bin/index.js 修改成 bin/yargs.js (用于备份)
- 进行安装 $
npm i commander -S
- 新建 bin/index.js 并编写
#!/usr/bin/env node const pkg = require('../package.json') const commander = require('commander'); // const { program } = commander; // 脚手架实例 program是一个单例 const program = new commander.Command(); // 这种手动实例化单例,同上,二取一 program .version(pkg.version) // 设定版本 .parse(process.argv) // 解析所有参数
- 执行 $
xyzcli --version
, 并查看结果1.0.0
- 执行 $
xyzcli --help
, 并查看结果Usage: xyzcli [options] Options: -V, --version output the version number -h, --help display help for command
- 这时候,使用 commander 完成了最小粒度的脚手架
- 这时候,可见,-V, -h 这种别名短称都已经默认给出了
3 )commander 通用全局配置
3.1 配置 usage
const program = new commander.Command(); // 这种手动实例化单例,同上,二取一
program
.usage(' [option]')
.version(pkg.version) // 设定版本
.parse(process.argv) // 解析所有参数
- 执行 $
xyzcli -h
, 查看输出Usage: xyzcli command> [option] Options: -V, --version output the version number -h, --help display help for command
- 可以看到
Usage: xyzcli [option]
- 可以看到
3.2 配置 name
const program = new commander.Command(); // 这种手动实例化单例,同上,二取一
program
.name(pkg.name)
.usage(' [option]')
.version(pkg.version) // 设定版本
.parse(process.argv) // 解析所有参数
-
这里修改下 package.json 中的 name,比如修改成 xyzcli111
-
执行 $
xyzcli -h
, 查看输出Usage: xyzcli111 command> [option] Options: -V, --version output the version number -h, --help display help for command
- 注意这里的,
Usage: xyzcli111 [option]
变成了 xyzcli111 - 验证完成,将 package.json 中的 name 从 xyzcli111 再修改回 xyzcli
- 注意这里的,
-
在实际应用中,我们会取 bin 属性中的第一个key (一般而言,bin里的配置和包名一致, 但是最好取bin的第一个key值)
const program = new commander.Command(); program // .name(pkg.name) .name(Object.keys(pkg.bin)[0]) // 注意这里 .usage(' [option]') .version(pkg.version) // 设定版本 .parse(process.argv) // 解析所有参数
-
这里不做输出测试
3.3 配置 option
const program = new commander.Command(); // 这种手动实例化单例,同上,二取一
program
// .name(pkg.name)
.name(Object.keys(pkg.bin)[0])
.usage(' [option]')
.versi服务器托管网on(pkg.version) // 设定版本
.option('-f, --first', '第一个')
.option('-s, --separator ', '使用分隔符分割', ',')
.option('-d, --debug', '开启调试模式', false)
.option('-e, --envName ', '获取环境变量名称')
.parse(process.argv) // 解析所有参数
- 执行 $
xyzcli -h
, 查看输出Usage: xyzcli command> [option] Options: -V, --version output the version number -f, --first 第一个 -s, --separator char> 使用分隔符分割 (default: ",") -d, --debug 开启调试模式 (default: false) -e, --envName envName> 获取环境变量名称 -h, --help display help for command
- 对参数进行解析和判断处理
const program = new commander.Command(); // 这种手动实例化单例,同上,二取一 program // .name(pkg.name) .name(Object.keys(pkg.bin)[0]) .usage(' [option]') .version(pkg.version) // 设定版本 .option('-f, --first', '第一个') // 选择第一个参数 .option('-s, --separator ', '使用分隔符分割', ',') .option('-d, --debug', '开启调试模式', false) .option('-e, --envName ', '获取环境变量名称') .parse(process.argv) // 解析所有参数 const options = program.opts(); // 获取所有可用的 opt 作为参数 const limit = options.first ? 1 : undefined; // 存在第一个参数, 则选1,不存在则不定义 console.log(program.args[0].split(options.separator, limit)); // 基于分隔符分割获取参数
- 执行,$
xyzcli -f x,y,z
,查看输出结果[ 'x' ]
- 执行,$
xyzcli -s / -f o/p/q
, 查看输出结果[ 'o' ]
4 ) 配置 command 命令
- 大类上还分两种小类型
- 调用 command api 注册命令
- 调用 addCommand api 注册命令
4.1 command
const program = new commander.Command(); // 这种手动实例化单例,同上,二取一
program
// .name(pkg.name)
.name(Object.keys(pkg.bin)[0])
.usage服务器托管网(' [option]')
.version(pkg.version) // 设定版本
.option('-f, --first', '第一个') // 选择第一个参数
.option('-s, --separator ', '使用分隔符分割', ',')
.option('-d, --debug', '开启调试模式', false)
.option('-e, --envName ', '获取环境变量名称')
// 定义一个克隆的命令
const clone = program.command('clone');
clone
.description('克隆仓库')
.action(() => {
console.log('do clone');
});
program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
- 直接执行 $
xyzcli
, 并输出Usage: xyzcli [option] Options: -V, --version output the version number -f, --first 第一个 -s, --separator 使用分隔符分割 (default: ",") -d, --debug 开启调试模式 (default: false) -e, --envName 获取环境变量名称 -h, --help display help for command Commands: clone 克隆仓库 help [command] display help for command
- 这里可以看到存在两个 command: clone 和 help
- 执行 $
xyzcli clone -h
, 并输出Usage: xyzcli clone [options] 克隆仓库 Options: -h, --help display help for command
- 执行 $
xyzcli clone
, 并输出do clone
- 对 clone 命令进行扩展
// 定义一个克隆的命令 const clone = program.command('clone [destination]'); clone .description('克隆仓库') .action((source, destination) => { console.log('do clone: ', source, destination); }); program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
- 执行 $
xyzcli clone
, 并输出error: missing required argument 'source'
- 可见source是必传项
- 而 destination 是可选项
- 执行 $
xyzcli clone ss dd
, 并输出do clone: ss dd
- 在clone命令中添加针对该命令的option
// 定义一个克隆的命令 const clone = program.command('clone [destination]'); clone .description('克隆仓库') .option('--fc, --force', '是否强制克隆', false) .action((source, destination, cmdObj) => { console.log('do clone: ', source, destination, cmdObj.force); }); program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
- 执行 $
xyzcli clone ss dd
, 并输出do clone: ss dd false
- 执行 $
xyzcli clone ss dd --fc
, 并输出do clone: ss dd true
- 注意,这里简称不能与前面定义的冲突,如果是多个字符,用
--
, 不能用一个-
- 这里
--fc
同--force
- 注意,这里简称不能与前面定义的冲突,如果是多个字符,用
- 执行 $
xyzcli clone --force ss dd
, 并输出do clone: ss dd true
- 注意这里更换了option的位置,只要在 clone 后面,就不会受到影响
4.2 addCommand
- addCommand 的特殊之处是可以注册子命令
// 定义service脚手架 const service = new commander.Command('service'); service .command('start [port]') .description('start service at some port') .action((port) => { console.log('service port @', port) }) program.addCommand(service); program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
- 执行 $
xyzcli -h
, 查看输出Usage: xyzcli [option] Options: -V, --version output the version number -f, --first 第一个 -s, --separator 使用分隔符分割 (default: ",") -d, --debug 开启调试模式 (default: false) -e, --envName 获取环境变量名称 -h, --help display help for command Commands: clone [options] [destination] 克隆仓库 service help [command] display help for command
- 执行 $
xyzcli service -h
, 查看输出Usage: xyzcli service [options] [command] Options: -h, --help display help for command Commands: start [port] start service at some port help [command] display help for command
- 这里看到 service 命令下存在一个子命令 start
- 可以看到,这种方式可以对命令进行分组,比如在 service 下 有start, 还可以有stop
// 定义service脚手架 const service = new commander.Command('service'); service .command('start [port]') .description('start service at some port') .action((port) => { console.log('service port @', port) }) service .command('stop') .description('stop service') .action((port) => { console.log('stop service') }) program.addCommand(service); program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
- 执行 $
xyzcli service -h
, 查看输出Usage: xyzcli service [options] [command] Options: -h, --help display help for command Commands: start [port] start service at some port stop stop service help [command] display help for command
- 执行 $
xyzcli service stop
, 查看输出stop service
- 通过子命令功能可大大扩展脚手架功能
- 注意,分组下的 子命令必须如上分开写,不能连写
4.3 )对命令注册进行自动匹配
- 可以通过 program.arguments 来监听所有命令输入
- 除了上面注册的命令,其他命令都会命中这里的 arguments 中
// 命令匹配 program .arguments(' [options]') .description('test command') .action((cmd, options)=> { console.log(cmd, options); }) program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
- 执行 $
xyzcli test
, 查看输出test undefined
- 执行 $
xyzcli
, 查看输出error: missing required argument 'cmd'
- 可以看到,这里 cmd 是要求强制输入的
- 执行 $
xyzcli tt ss
, 查看输出tt ss
- 执行 $
xyzcli -h
, 查看输出Usage: xyzcli [option] test command Options: -V, --version output the version number -f, --first 第一个 -s, --separator 使用分隔符分割 (default: ",") -d, --debug 开启调试模式 (default: false) -e, --envName 获取环境变量名称 -h, --help display help for command Commands: clone [options] [destination] 克隆仓库 service
- 可以看到这里没有什么信息,只有 一个 test command 的描述
- 执行 $
xyzcli test -h
, 同样也看不到其他实用的信息 - 现在,对其再次进行修改,测试
// 命令匹配 program .arguments(' [options]') .description('test command', { cmd: 'command to run', options: 'options for command' }) .action((cmd, env)=> { console.log(cmd, env); }) program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
- 执行 $
xyzcli test -h
, 查看输出结果Usage: xyzcli [option] test command Arguments: cmd command to run options options for command Options: -V, --version output the version number -f, --first 第一个 -s, --separator 使用分隔符分割 (default: ",") -d, --debug 开启调试模式 (default: false) -e, --envName 获取环境变量名称 -h, --help display help for command Commands: clone [options] [destination] 克隆仓库 service
- 可以看到,这里多了 Arguments 这一项,里面的描述配置都有说明
- 它的强大之处在于,可以匹配到所有输入的命令, 同时强制必须传 cmd 命令
- 这个功能和在yargs框架中的
demandCommand
功能类似 - 还有一种方式,也同样强大,如下
program .command('install [name]', 'install package') program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
- 执行 $
xyzcli -h
, 查看输出结果Usage: xyzcli [option] test command Arguments: cmd command to run options options for command Options: -V, --version output the version number -f, --first 第一个 -s, --separator 使用分隔符分割 (default: ",") -d, --debug 开启调试模式 (default: false) -e, --envName 获取环境变量名称 -h, --help display help for command Commands: clone [options] [destination] 克隆仓库 service install [name] install package
- 可以看到,最后的 install
- 如果执行 $
xyzcli install -h
, 查看发现报错- 报错信息为:
Error: 'xyzcli-install' does not exist
- 它会把当前脚手架 xyzcli 加上 -install 组成一个新的命令
xyzcli-install
- 而这个命令在我们电脑上是没有的
- 这个命令有些像 $
npm init install
当输入这个方法的时候也会报错 - 它会告诉你,
'create-install@latest' is not in the npm registry.
- 这是因为,npm init 命令后面加上参数时,比如 加上 abc, 就是
npm init abc
- 默认会在前面加上 create, 然后找这个包,也就是
create-abc
这个包 - 如果这个包存在,则动态下载并执行这个包, 这块了解即可
- 报错信息为:
- 还可以加上别名
program .command('install [name]', 'install package') .alias('i') program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
- 执行 $
xyzcli -h
, 查看输出结果Usage: xyzcli [option] test command Arguments: cmd command to run options options for command Options: -V, --version output the version number -f, --first 第一个 -s, --separator 使用分隔符分割 (default: ",") -d, --debug 开启调试模式 (default: false) -e, --envName 获取环境变量名称 -h, --help display help for command Commands: clone [options] [destination] 克隆仓库 service install|i [name] install package
- 可以看到上述别名起作用了
- 同时,还可以添加第三个options参数
program .command('install [name]', 'install package', { executableFile: 'npm', // 手动修改可执行文件 }) .alias('i') program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
- 这时候我们执行 $
xyzcli i i vue -S
- 这里的 xyzcli i 或 xyzcli install 等价于 npm
- 所以,这时候,xyzcli i i vue -S 等价于 npm i vue -S
- 执行后,可见 package.json 中存在了 vue
- 这里很奇怪的是: 两个 i, 但是这个问题不大
- 还有一些其他的配置,比如:
program .command('install [name]', 'install package', { executableFile: 'npm', // 手动修改可执行文件 isDefault: true, // 默认会匹配这个 // hidden: true, // 不再帮助信息中显示 }) .alias('i') program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
- 这里 isDefault 设置为 true时,当执行 $
xyzcli
就直接会匹配到npm
命令的帮助信息 - 这里 hidden 设置为 true时,在帮助信息中就看不到 install 命令了
- 这里 isDefault 设置为 true时,当执行 $
全部example参考
#!/usr/bin/env node
const pkg = require('../package.json')
const commander = require('commander');
// const { program } = commander; // 脚手架实例 program是一个单例
const program = new commander.Command(); // 这种手动实例化单例,同上,二取一
program
// .name(pkg.name)
.name(Object.keys(pkg.bin)[0])
.usage(' [option]')
.version(pkg.version) // 设定版本
.option('-f, --first', '第一个') // 选择第一个参数
.option('-s, --separator ', '使用分隔符分割', ',')
.option('-d, --debug', '开启调试模式', false)
.option('-e, --envName ', '获取环境变量名称')
// 定义一个克隆的命令
const clone = program.command('clone [destination]');
clone
.description('克隆仓库')
.option('--fc, --force', '是否强制克隆', false)
.action((source, destination, cmdObj) => {
console.log('do clone: ', source, destination, cmdObj.force);
});
// 定义service脚手架
const service = new commander.Command('service');
service
.command('start [port]')
.description('start service at some port')
.action((port) => {
console.log('service port @', port)
})
service
.command('stop')
.description('stop service')
.action((port) => {
console.log('stop service')
})
program.addCommand(service);
// 设定 install 命令
program
.command('install [name]', 'install package', {
executableFile: 'npm', // 手动修改可执行文件
// isDefault: true,
// hidden: true,
})
.alias('i')
// 命令匹配,用于兜底
program
.arguments(' [options]')
.description('test command', {
cmd: 'command to run',
options: 'options for command'
})
.action((cmd, env)=> {
console.log(cmd, env);
})
program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
相关推荐: 热点!AI 大模型直通车已正式开启,快抓住就业机遇跳板!
动弹” 回归,赶紧下载 APP 愉快地摸鱼吧!” 关注行业前瞻性,开启AI大模型新时代 目前互联网就业形势展现出一种复杂而多元的局面。伴随着新型技术的不断更新迭代与就业人群基数的不断升高,对AI专业人才的技术要求可谓是达到了一定高度。对AI技术人才求贤若渴,岗…