1、命令行工具
命令行工具(Cmmand Line Interface)简称cli,顾名思义就是在命令行终端中使用的工具。我们常用的 git 、npm、vim 等都是 cli 工具,比如我们可以通过 git clone 等命令简单把远程代码复制到本地。
再比如:vue的 vue-cli
;acro 的 arco-cli
;vite的 npm create vite@latest
;nest 的 nest-cli
等等
2、如何开发一个 node 命令行工具
2.1、初始化项目
- 创建一个文件夹,执行 npm 初始化命令
npm init -y
- 创建 src 文件夹,然后创建 index.js 文件,并写入以下代码
#!/usr/bin/env node
console.log("hello world!");
里面的第一行代码,是告诉终端,这个文件要使用 node 去执行。具体含义需要百度了
2.2、本地创建命令
一般 cli都有一个特定的命令,比如 node、npm、pnpm、nest、arco 等等,所以我们也要给这个工具设置一个命令,比如
ncr
需要修改
package.json
文件 , 要加上bin
这个属性,值是对象, 对象里面是 键值对 ,键是 命令名称,值是 入口文件路径
{
"name": "ncr",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"ncr": "./src/index.js"
},
"keywords": [],
"author": "",
"license": "ISC"
}
然后 还需要再根目录执行一下
npm link
, 有下面这个输出就对了
然后 终端 执行
ncr
,可以看到 hello world 就对了
2.3 实现获取版本信息命令 commander
如若再终端,输入 ncr -v --version ,我们想获取到 当前工具版本
先修改 src/index.js
#!/usr/bin/env node
console.log("hello world!");
console.log(process.argv);
process.argv 这个属性的返回值,是数组,数组的第二项往后,就是 用户输入的命令
commander
这个库,可以解析命令行的参数,一般再开发命令行工具的时候,都会用这个
npm i commander
#!/usr/bin/env node
const pkg = require("../package.json");
const { program } = require("commander"); // 解析 命令行 参数的库
// 设置 -h 选项的 用法
program.name("ncr").usage("[options]");
// program.version(pkg.version, "-v, --version", "获取 ncr 版本");
// 添加选项
program.option("-v, --version", "获取 ncr 版本");
program.option("-h, --help", "获取帮助信息");
// 处理选项
program.action(() => {
let options = program.opts();
console.log("option 获取");
if (options.help) {
console.log(`
███╗ ██╗ ██████╗██████╗
████╗ ██║██╔════╝██╔══██╗
██╔██╗ ██║██║ ██████╔╝
██║╚██╗██║██║ ██╔══██╗
██║ ╚████║╚██████╗██║ ██║
╚═╝ ╚═══╝ ╚═════╝╚═╝ ╚═╝
`);
console.log(program.helpInformation());
console.log(
"---------------------------------------------------------------------------------------"
);
console.log("欢迎使用~~~~~");
console.log(
"---------------------------------------------------------------------------------------"
);
} else if (options.version) {
console.log(chalk.blue.bgMagenta.bold(`当前版本号是: ${pkg.version}`));
}
});
这个时候再终端输入
ncr -h
就会看到以下结果
Usage: index [options] 这一段也是可以修改的;Usage 就是用法的意思
program.name("ncr").usage("[options]");
2.4、终端输出增加颜色
需要用到
chalk
这个库
npm install chalk
const chalk = require("chalk"); // 让终端输出 增加一些样式
console.log(chalk.blue.bgMagenta.bold(`当前版本号是: ${pkg.version}`));
终端输入 ncr -v 终端报错
const chalk = require("chalk"); // 让终端输出 增加一些样式
^
Error [ERR_REQUIRE_ESM]: require() of ES Module F:\个人项目\ncr\node_modules\chalk\source\index.js from F:\个人项目\ncr\src\index.js not supported.
Instead change the require of F:\个人项目\ncr\node_modules\chalk\source\index.js in F:\个人项目\ncr\src\index.js to a dynamic import() which is available in all CommonJS modules.
at Object.<anonymous> (F:\个人项目\ncr\src\index.js:5:15) {
code: 'ERR_REQUIRE_ESM'
}
如若出现这个错误,就降低
chalk
的版本,换成 4 版本的
2.5、ncr current 命令 代码编写
// index.js
const { getRegistry } = require("./utils");
program
.command("current")
.description("查看当前npm镜像源")
.action(() => {
console.log(
"当前npm镜像源是: " + chalk.blue.bgMagenta.bold(`${getRegistry()}`)
);
});
// src/util/index.js
const { exec, execSync } = require("child_process"); //子线程用于执行shell命令
exports.getRegistry = function () {
// 默认返回 buffer 格式,
return execSync("npm get registry", { encoding: "utf-8" });
};
2.6、ncr list 命令代码编写
registry.json
{
"npm": {
"registry": "https://registry.npmjs.org/",
"ping": "https://registry.npmjs.org/"
},
"yarn": {
"registry": "https://registry.yarnpkg.com/",
"ping": "https://registry.yarnpkg.com/"
},
"taobao": {
"registry": "https://registry.npmmirror.com/",
"ping": "https://registry.npmmirror.com/"
}
}
// 查看所有的 npm 镜像源
const registryList = require("./registry.json");
program
.command("list")
.alias("ls") // 起个别名,也可以用 aliases方法,传递一个数组,设置多个别名
.description("查看所有的npm镜像源")
.action(async () => {
let curRegistry = getRegistry();
Object.entries(registryList).forEach((f) => {
console.log(
// 一定要加 trim
(f[1].registry.trim() === curRegistry.trim()
? chalk.blue.bgMagenta.bold("*")
: " ") +
" " +
f[0].padEnd(15, "-") +
" " +
f[1].registry
);
});
});
2.7、ncr use 命令代码编写
切换源
// 使用某个 npm 镜像源
const inquirer = require("inquirer"); // 交互式命令工具
program
.command("use")
.description("切换npm镜像源")
.action(() => {
inquirer
.prompt([
{
type: "list",
name: "select",
message: "请选择npm镜像源",
choices: Object.keys(registryList).map((f) => f),
},
])
.then((res) => {
// res { select: 'yarn' }
let registryUrl = registryList[res.select].registry;
exec(
`npm config set registry ${registryUrl}`,
(error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log("切换成功!");
}
);
});
});
3、发布npm
先把npm的 registry 切换到官方的镜像源
npm login 先登录一下
然后 执行 npm publish
403
错误,大多数情况是 包的name 重名了
这样就是成功了!
总结
解析命令行的工具
- Yargs
- yargs-parser
- arg
- minimist
- commander
参考链接
- chalk GitHub文档
- inquirer GitHub文档
- commander GitHub文档
- node api