为什么是 Node
Node 拥有最为庞大的生态社区,数十万的 Package,其中有许多 Package 是专门为建强大的 CLI 工具打造的。在社区生态的帮助下,你可以更快速构建更强大的 CLI 工具。同时,在 NPM、Yarn 等 Package 管理工具的帮助下,你也可以快速的分发的你的 CLI 工具,让你的用户更简单的使用你的 CLI 工具。
快速开始
初始化项目
mkdir cli-tool && cd cli-tool
npm init --yes
创建 src/cli.js
,写入如下内容:
// src/cli.js
module.exports = function cli() {
// 打印命令参数
console.log(process.argv);
};
创建 bin/cli.js
文件,这是 CLI 工具的入口文件,写入如下内容:
#!/usr/bin/env node
const cli = require("../src/cli");
cli();
重点:修改 package.json
,写入 bin
字段,添加 cli
命令
{
"name": "cli-tool",
"version": "1.0.0",
"description": "",
"main": "src/cli.js",
"bin": {
"cli": "bin/cli.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
在项目根目录下,运行:
npm link
在终端中输入 cli
命令,即可打印出如下类似内容:
[
'/Users/xx/.nvm/versions/node/v12.16.2/bin/node',
'/Users/xx/.nvm/versions/node/v12.16.2/bin/cli'
]
至此,一个简单的 Node CLI 工具就完成了。
基本原理
bin
NPM 实现了将 Package 中的可执行文件添加全局 PATH 中的能力,当在 package.json
文件中添加 bin
字段时,NPM 会将 bin
声明的文件链接(软链接)到 bin
目录中(全局可用),或者 ./node_modules/bin/
(本地可用)。
如下面的 bin
创建 /usr/local/bin/myapp
到 cli.js
的软链接:
{ "bin" : { "myapp" : "./cli.js" } }
同时,我们要在 bin
声明的文件的开头添加 #!/usr/bin/env node
声明,确保系统会用 Node 执行此文件。
npm link
npm link
命令会创建当前 Package 到 Gloabl 的软链接,使当前 Package 在全局可用,类似虚拟的 npm i --global packae
命令,在本地调试时十分有用。
实践
参数解析
CLI 工具的基本能力就是要解析用户输入的 CLI 命令与参数,实现相关功能。Node 的 process.argv
数组包含了 Node
进程被启动时传入的命令行参数,通过解析 process.argv
数组即可,社区中相关的 Package 也比较多,如:yargs,minimist 等。
这里推荐使用 [commander](https://github.com/tj/commander.js)
构建你的 CLI 工具,commander 是一个较为完善的 Node CLI 解决方案,拥有解析输入参数、关联处理逻辑、输出命令提示等功能。只有当 commander 的功能无法满足你的需求时,才建议你尝试自己处理命令参数解析。
交互输入
在某些情况下,CLI 工具可能需要使用交互式输入,如输入密码时,这种情况不适合直接通过参数输入。简单的输入时,可以直接 Node 的 readline
模块:
const readline = require("readline");
const question = ["请输入您的姓名", "请输入您的年龄"];
const result = [];
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: `?${question[0]} `,
});
rl.prompt();
rl.on("line", (line) => {
result.push(line.trim());
const max = result.length;
if (max === question.length) {
rl.close();
}
rl.setPrompt(`?${question[max]} `);
rl.prompt();
}).on("close", () => {
console.log(`谢谢参与问答 *** 姓名: ${result[0]} 年龄: ${result[1]}`);
process.exit(0);
});
当需要比较复杂的交互时,如列表选择时,就需要使用社区中的 Package 了。这里推荐 enquirer,功能较为强大,如下:
发布
最后,你可以通过 NPM 将你的 Node CLI 工具快速分发出去:
# 登陆 npm
npm adduser
# 打 Tag
npm tag v1.0.0
# 发布
npm publish