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 nodeconsole.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 nodeconsole.log("hello world!");
console.log(process.argv);
process.argv 这个属性的返回值,是数组,数组的第二项往后,就是 用户输入的命令
commander
这个库,可以解析命令行的参数,一般再开发命令行工具的时候,都会用这个
npm i commander
#!/usr/bin/env nodeconst 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