前端脚手架:命令行解析库commander的使用教程
我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第11篇文章,点击查看活动详情
利用nodejs
开发一个前端脚手架,首先面临的问题是如何定义并解析命令行的命令、参数、配置等信息。业界流行的两个库是yargs
和commander
,其中commander
更为强大,本文将详细介绍commander
的使用。
全局配置options
获取program
对象有两种方式:
// 获取commander单例
const { program } = commander
// 手动实例化一个commander实例
const program = new commander.Command();
#!/usr/bin/env node
const commander = require('commander')
const pkg = require('../package.json')
const program = new commander.Command()
program.usage('<command> [options]')
program.version(pkg.version)
program.parse()
commander
会默认有两个全局配置(options) --versiong -V 和 --help -h
,因此你可以执行下面语句:
test-cli -V // 1.0.0
除了默认全局配置,我们还可以增加自己定义的全局配置:
// 第三个参数是默认值
program.option('-d, --debug', '是否开启调试模式', false)
// -e 后面必须要输入值,因为<>表示必填
program.option('-e, --envName <envName>', '获取环境变量')
执行test-cli -h
:
如果获取options
的值呢?
// 获取所有options的值
program.opts()
全局配置options有四种写法,如下:
serve -p 80
serve -p80
serve --port 80
serve --port=80
我们一般采用serve -p 80
和 serve --port=80
这两种写法。
命令注册
先看一个最简单的例子:
program
.command('clone [source] [destination]')
.description('clone a repository into a newly created directory')
.option('-s, --separator <char>', 'separator character', ',')
.action((source, destination, options) => {
console.log('source', source)
console.log('destination', destination)
console.log('options', options)
})
执行:
test-cli clone index.js out.js -s /
// 打印结果:
source index.js
destination out.js
options { separator: '/' }
【注意】
<>
表示必填,[]
表示可选
上面的那种写法把命令的参数(source, destination)和命令写在一起,其实我们可以分开写(推荐分开写):
program
.command('split')
.description('分割字符串')
// 用<>表示是一个必输的字符,[]表示可输
.argument('<string>', 'str to split')
.argument('<array>', 'str to split')
.option('-s, --separator <char>', 'separator character', ',')
.action((str, array, options) => {
console.log('str', str)
console.log('array', array)
console.log('options', options)
})
假如你的命令很多,需要对命令进行分组,这样方便管理,怎么做呢?需要使用addCommand
这个api:
// 定义了一个service命令
const service = new commander.Command('service')
// 在service命令对象上注册子命令start和stop
service
.command('start [port]')
.description('service start at port')
.action(port => {
console.log('service at' + port)
})
service
.command('stop')
.description('stop service')
.action(() => {
console.log('stop service')
})
program.addCommand(service)
如何调用其他的脚手架
在你的脚手架上调用其他的第三方脚手架,实现脚手架的串行使用,可以使你的脚手架功能大大增强。
command
方法有两种使用,它用一个函数重载来实现的:
command(nameAndArgs: string, opts?: CommandOptions): ReturnType<this['createCommand']>;
command(nameAndArgs: string, description: string, opts?: ExecutableCommandOptions): this;
当我们在command
命令中传入脚手架命令和命令描述时,它的使用就有点不一样了,看下面代码:
program.command('install [name]', 'install package')
当执行命令test-cli install
时,它会报错test-cli-install
不存在,也就是当你执行上面命令时会帮你拼接成一个新的命令test-cli-install
,这有点类似于npm init aaabbb
这个命令,这个命令执行时会报'create-aaabbb@latest' is not in this registry
,因为它会在aaabbb
前面加上create
然后去下载create-aaabbb
包。
所以,如果你想再执行test-cli install
不报错,可以加上第三个参数:
program
.command('install [name]', 'install package', {
executableFile: 'vue'
})
当你执行test-cli install
时,它实际上是执行vue
这个脚手架。
所以当你执行test-cli install create test-name
,就是在执行vue create test-name
。
这样就会让你脚手架可以利用别人的脚手架做很多事情,这个功能非常有用。
监听
对options的监听
现在我要对--debug
进行监听,如果有输入--debug
就执行回调函数,这个回调函数要早于命令的回调函数。
program.on('option:debug', () => {
process.env.LOG_LEVEL = 'verbose'
})
对command的监听
如果用户输入一个我们没有定义的命令,那么需要给用户提供一个纠错信息,那么就可以使用监听功能。
program.on('command:*', obj => {
console.error('未知的命令:' + obj[0])
// 获取已经注册的命令
const availableCommands = program.commands.map(cmd => cmd.name())
console.log('可用命令:' + availableCommands.join(','))
})
对于上面的功能除了使用监听外,还可以使用program.arguments
,这是一个兜底的命令,也就是用户输入的命令我们没有定义,那么就走到program.arguments
里面的逻辑。
program
.arguments('<cmd> [options]')
.description('未知命令')
.action(function (cmd) {
console.log('arguments', cmd)
})
除了program.arguments
外,其实还有一个配置能实现兜底的功能,即isDefault: true
:
// command可以传一个opts选项
program
.command('clone [source] [destination]', {
isDefault: true
})
.action((source) => {
console.log('source')
})
当输入test-cli aaa
时,因为aaa
没有注册,那么就执行clone
命令。
转载自:https://juejin.cn/post/7148650138053902372