现在我们先写一个简单的文件来理解 (也推荐先自行预览一下 commander 官方文档), 下面是 bin 文件夹的 cli-test, 代码如下:
- #!/usr/bin/env node
- const program =require('commander');
- program
- .usage('[option]', '--type required')
- .option('--type [typeName]', 'type: dev && build')
- .parse(process.argv);
- const {type} = program;
- if(type == 'dev'){
- console.log('do something', type)
- }else if(type == 'build'){
- console.log('do something', type)
- }else{
- console.log('params error');
- program.help();
- }
解释一下上面的代码, 从查看源码里发现 require('commander') 会 new 一个 commander 内部的单例对象并返回, program 已经是一个实例,
. .usage 仅仅描述了参数规则, 会在 --help 中打印出来..option 定义了一个参数名和描述, parse 会解析命令之中的参数, 根据上面定义好的规则执行相关命令. 比如上面的代码定义了 option 类型的参数 --type, 执行 .parse 的时候, parse 根据 process.argv 之中的参数, 获取到 --type, 并把参数命和参数值存储在内部 commander 实例的属性之中, 因此后面的代码就能从 program 之中取到 type, 如果 type 不存在或者不是我们约定的值, 最后我们打印参数错误, 并执行 help 方法打印了 --help. 如下截图, 我们 node 执行 cli-test, 因为没有约定参数, 所以执行了 else 的程序.(因为这里是本地的 demo 程序, 所以直接使用 node 命令)
接着, 我们执行正确的命令参数, 如下
这样一个简单的 demo 就实现了, 看起来也挺简单的, commander 封装了一些也不算很复杂的功能.
再来一个例子:
新建了两个文件, 要以 bin 命令的执行文件命后面加上 -name, 作为子命令文件
- cli-test:
- #!/usr/bin/env node
- const program =require('commander');
- program
- .usage('<command> [option]', 'option --type required')
- .command('h5', 'to h5')
- .command('rn', 'to rn')
- .parse(process.argv);
- cli-test-h5:
- #!/usr/bin/env node
- const program =require('commander');
- program
- .option('--type [typeName]', 'type: dev && build')
- .parse(process.argv);
- const {type} = program;
- if(type == 'dev'){
- console.log('do something h5', type)
- }else if(type == 'build'){
- console.log('do something h5', type)
- }else{
- console.log('params error');
- program.help();
- }
- cli-test-rn:
- #!/usr/bin/env node
- const program =require('commander');
- program
- .option('--type [typeName]', 'type: dev && build')
- .parse(process.argv);
- const {type} = program;
- if(type == 'dev'){
- console.log('do something rn', type)
- }else if(type == 'build'){
- console.log('do something rn', type)
- }else{
- console.log('params error');
- program.help();
- }
先直接运行 3 个命令运行程序, 看下结果, 而后分别解释一下:
node ./bin/cli-test:
定义了. command 子命令却没有相应执行参数, commander 对象会直接打印 - help, 并 process.exit 退出进程.
node ./bin/cli-test h5 --type dev:
cli-test 通过 command 方法约定子命令名称和描述, 如 h5, 当执行 node cli-test h5 --type dev 的时候, cli-test 执行到 .command('h5', 'to h5'), 会在当前 commander 实例内部, new 一个 name 为 h5 的子 commander, 存储在当前父实例的 commands 数组中, 当 .parse(process.argv) 执行, 获取到参数中 h5 后, 在 commands 里查找是否有 name 为 h5 的 commander 子实例, 如果查找到, 启动一个子进程按照命名规则执行 cli-test-h5 文件并带入后面的 option 参数. 这样 commander 就帮助我们实现了多文件命令划分, 我们可以把不同类型的执行代码放在不同的文件中.
node ./bin/cli-test h5 --type dev:
同上
小结
bin 文件夹下的这 3 个 node 文件他们都是 commander 实例, commander 库只是一个简单的封装, 帮助定义 多文件命令, 执行参数 , 简易文档, 参数验证等. 以上就是 commander 的大致使用和我对其的理解. 源码不多, 建议可以深入学习一下.
最后
到最后大家结合实现以上所说的 cli 和 commander, 一个 commander 实现的命令行工具就能完成了, 是不是很简单!?
注意
如果执行命令发现报错为 error: xx(1) not executable. try chmod or run with root, 要注意下创建的文件类型.
来源: https://www.cnblogs.com/1wen/p/10142210.html