使用 yargs 构建 Node.js CLI
照片由Gregory Culmer拍摄,来自Unsplash
作为开发人员,我们每天都会使用命令行工具。我们使用它们来简化工作中的常见任务:
- 包装
- 绒毛
- 构建应用程序
- 部署应用程序
- 发布软件包
- 实现很多事情的自动化……
但这还不是全部。其中很多都与开发无关!以下是命令行应用程序列表。
我开发了一些命令行工具,例如gitmoji-changelog 。它是一个用于生成符合gitmoji提交规范的变更日志的工具。我还为gatsby-cli做出了贡献,它可以帮助开发者使用 React 构建速度极快的网站和应用程序。所有这些工具都是用yargs实现的。
为什么要使用 yargs?
既然Node.js为我们提供了构建 CLI 应用程序所需的所有工具,为什么还要使用yargs?
一个好例子胜过千言万语。让我们来创建一个简单的命令行应用程序。调用它时,它会显示Hello world!……
真是个绝妙的例子!
该命令行工具接受一个参数来覆盖默认world的单词。它还接受一个命名选项times来多次记录消息。
我们将逐步构建它,yargs然后再使用它重构代码库。
首先,我们创建一个index.js包含以下内容的文件。
console.log('Hello world!')
我们使用以下命令执行文件node,并将消息打印到控制台中。
foo@bar:~$ node index.js
Hello world!
好的,参数可以在argv全局变量的属性中找到process。第一个参数是可执行文件的路径,第二个参数是已执行的 JavaScript 文件的路径。
[
"~/.nvm/versions/node/v10.15.3/bin/node",
"~/index.js"
]
如果我们使用参数调用命令行界面 (CLI),它将返回此数组的第三个元素。我们通过写入该元素来获取其值process.argv[2],并world在未提供该元素时将其用作默认值。
const args = process.argv
const name = args[2] || 'world'
console.log(`Hello${name}!`)
调用命令行界面,现在可以覆盖了world!
foo@bar:~$ node index.js you
Hello you!
事情会变得非常复杂!记住,我们希望添加一个选项,允许多次显示该消息。可选参数通常像这样表示--times 3。它们可以放在你想要的任何位置。
我们首先处理可选参数位于名称参数之后的情况。
const args = process.argv
const name = args[2] || 'world'
const times = args[4] || 1
for (let i = 0;i < times; i++) {
console.log(`Hello${name}!`)
}
调用命令行界面后,该消息会显示三次!
foo@bar:~$ node index.js you --times 3
Hello you!
Hello you!
Hello you!
如果不提供 name 参数,之前的代码将无法运行。即使将可选参数放在 name 参数之前,它也无法运行。
我们修改代码以处理可选参数位于第一个位置的情况。
// ...
if (args[2] === '--times') {
name = args[4]
times = args[3]
}
// ...
当放在名称之后时,我们保持相同的行为。
// ...
} else if (args[3] === '--times') {
name = args[2]
times = args[4]
}
// ...
这里提供了名称参数,但没有提供可选参数。
// ...
} else if (args[2] && args[2] !== '--times') {
name = args[2]
}
// ...
以下是最终代码。
const args = process.argv
let times = 1
let name = 'world'
if (args[2] === '--times') {
name = args[4]
times = args[3]
} else if (args[3] === '--times') {
name = args[2]
times = args[4]
} else if (args[2] && args[2] !== '--times') {
name = args[2]
}
for (let i = 0;i < times; i++) {
console.log(`Hello ${name}!`)
}
它有点复杂,不太容易读懂。而且,如果我们添加一个新的位置参数,它就无法正常工作了。
使用 yargs 重构我们的 CLI 应用程序
为了构建一个可维护且可扩展的命令行应用程序,我们将使用yargs。它公开了许多功能,其文档中有详细的描述。我们将使用 `command` 函数。它接受四个参数:名称、描述、构建器和处理程序。如果将 `name` 参数设置为 `null`*或$0`default`,则使用默认命令。
require('yargs')
.command('$0 [name]', 'start the server',() => {}, () => {
console.log('Hello world!')
})
这段代码稍微复杂一些,仅仅是为了显示一条Hello world!消息。随着代码变得越来越复杂,它会变得更有趣。我们来添加名称参数。它将在构建器参数中完成,该参数是一个函数,它接收 yargs 实例作为参数。我们使用位置函数来描述参数。正如你所看到的,它直接接受一个默认值。
require('yargs')
.command('$0 [name]', 'start the server',(yargs) => {
yargs
.positional('name', {
describe: 'name to display',
default: 'world'
})
}, () => {
console.log(`Hello world!`)
})
参数作为参数传递给处理函数。它是一个对象,每个参数都有一个对应的属性。我们给参数命名name,它的值可以在argv.name该属性中获取。
require('yargs')
.command('$0 [name]', 'start the server',(yargs) => {
yargs
.positional('name', {
describe: 'name to display',
default: 'world'
})
}, (argv) => {
console.log(`Hello ${argv.name}!`)
})
是时候见识一下它的强大之处了。我们使用选项yargs函数添加可选参数,它的 API 与类似。别忘了添加默认值。默认值与原始实现中的相同。timespositionalfor
require('yargs')
.command('$0 [name]', 'start the server',(yargs) => {
yargs
.positional('name', {
describe: 'name to display',
default: 'world'
})
.option('times', {
alias: 't',
type: 'number',
default: 1,
description: 'number of times the message is logged'
})
}, (argv) => {
for (let i = 0;i < argv.times; i++) {
console.log(`Hello ${argv.name}!`)
}
})
如您所见,我们无需处理编写 CLI 应用程序的技术复杂性,yargs它为我们处理了这一切。
额外福利:它还附带帮助选项
yargs它会自动为您添加命令help!它使用我们在描述界面时提供的信息。
foo@bar:~$ node index.js --help
yargs.js [name]
start the server
Positionals:
name name to display [default: "world"]
Options:
--help Print the help [boolean]
--version Print the version number [boolean]
--times, -t number of times the message is logged [number] [default: 1]
一切就绪🙌
现在你可以构建所有你梦寐以求的命令行应用程序了!
我创建了一个存储库,其中包含了本文中提到的所有资源。
非常感谢您的反馈🙏 如果您有任何问题,请在推特上联系我@YvonnickFrin!
文章来源:https://dev.to/yvonnickfrin/build-a-node-js-cli-using-yargs-2hd