从 0 编写 cli ,原来自己写一个 cli 也不难嘛~
公司里写前端代码这么多年,看着周围的小伙伴还在用着各种不同的工具来进行创建项目、打包项目、发布项目,就想着我得为他们做点什么~
要么,我们把这些常用高频功能集成到一个 CLI 里好啦!
再手撸一个 CLI 之前,我想先问一下:
CLI 是什么?
官方介绍:
命令行界面(英语:command-line interface,缩写:CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。
像我们常用的 npm install
、npm run xxx
这些都属于 CLI 命令。
那如何基于 nodejs 编写自定义 CLI 库呢?
先别被自己手写 CLI 吓退,其实也没有那么复杂,说白了
- 写一段 nodejs 脚本,干了某件事
- 给这段脚本命个名叫 xxx
- 然后把这个脚本注册到全局
最后,我们就可以愉快的访问 xxx 啦!
郑重说明,我没有在开玩笑,实际上就是这个流程而已,很多事情甚至 npm 已经帮我们完善的很简单啦!
怎么创建?
1、新建项目
先随便找个文件夹,然后初始化项目 npm init
,这个都会是吧,那我们过~
2、编辑 package.json
{
"name": "my-vue",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"type": "module", // 这里如果不用 ESM 的话可以不用加
"bin": {
"my-vue": "index.js"
}, // 这里才是重中之重
"dependencies": {
...
}
}
我们发现这里比我们以往写的项目多了一个 bin
,那么 bin
里面的对象代表什么意思呢?
其实啊,bin
中的 my-vue
相当于我们给我们的 CLI
命了名,然后指向我们的入口文件 index.js
。
通过 npm link
命令可以把我们的库在 node 全局建立一个软链接,相当于我们 npm install -g my-vue
一样,可以通过 my-vue
直接访问到指向的 index.js
文件
这个时候需要在目录下新建一个 index.js
文件,然后在第一句写这么一句话
#!/usr/bin/env node
这是为了告诉系统该脚本要用 node 环境来执行
#!/usr/bin/env node
console.log("进来啦");
然后,我们在命令行执行 my-vue
就能看到这样的结果
小结一下
- 编辑 package.json ,通过 bin 属性,给我们的包命名
- 通过 npm link 命令将包在全局注册
- 命令行访问 my-vue 查看输出
自己写的 CLI
已经可以运行了,开心撒花,那我们今天的分享到这里就结束啦~
......
小儿科了不是,我们继续往下看
怎么写命令?
通过上一环节,我们已经可以成功的在命令行里执行我们的代码了
接下来我们要像 vue-cli 那样用 vue create app 这样的命令来做一些事情。
这个时候就要用到大名鼎鼎的 commander
库,毕竟它是 nodejs 作为命令行界面的完整解决方案,不服不行啊。
简单介绍一下这个库:
import { program } from "commander";
// 用来声明库的版本号
program.version("1.0.0");
// Commander 的第一个参数为命令名称。
// 命令参数可以跟在名称后面,也可以用`.argument()`单独指定。
// 参数可为必选的(尖括号表示)、可选的(方括号表示)或变长参数(点号表示,如果使用,只能是最后一个参数)
program
.command("init <app-name>");
// 该命令的描述,可选的
.description("create a new project by my-template")
// Commander 使用`.option()`方法来定义选项,同时可以附加选项的简介。
// 每个选项可以定义一个短选项名称(-后面接单个字符)和一个长选项名称(--后面接一个或多个单词),使用逗号、空格或`|`分隔。
.option("--v3", "create a new project by my-template-v3")
.option("-p, --pc", "create pc template")
.option("-a, --app", "create app template")
.option("-f, --force", "force update template")
// 命令处理函数的参数,为该命令声明的所有参数,除此之外还会附加两个额外参数:
// 一个是解析出的选项,另一个则是该命令对象自身。
.action((name, options, command) => {
...
}
// 声明多个命令直接注册即可
program
.command("publish")
.description("publish project to remote server")
.option("-c, --config <key name>", "publish upload config,config is sftp.config.js key name")
.action((options) => {
...
});
// 解析命令行中的输入,根据输入内容匹配相对应的命令实现
program.parse()
详细的使用教程可以去 GitHub 仓库查看,传送门
好,有了基本的命令结构,我们只需要专注于功能实现即可。
那上面的代码为例,我们通过命令配合多个选项组合,基本可以实现定制初始化工程模板以及工程发布行为。
小结一下
- npm install commander
- 通过全局的 program 创建自己的命令,以及配置可选项
- 实现相关业务逻辑
一键安装
对于多人协作的情况下,这么一套自定义命令行如何快速推广呢?
- 注册
npm
账号,发布 CLI 到公共仓库,小伙伴们通过npm install -g my-vue
来进行全局安装并使用 - 很多情况下公司内部定制的 CLI 都是内部使用的,也没有必要发布到公共仓库,我们可以让小伙伴从代码仓库拉到本地,
install
之后再npm link
即可。
针对第二种方案,为了减少小伙伴的心智负担,我们可以写一个 install
脚本,拉下来之后直接执行 install
脚本来完成一键安装,简单好用。
这里分享一下我的 install
脚本,这个脚本依赖了一个好用的 shelljs
库,可以在 node
环境执行 shell
脚本,大家有兴趣可以学习一下
import shelljs from "shelljs";
// 兼容大家本地的各种包管理工具
if (shelljs.which("pnpm")) {
shelljs.exec("pnpm install");
} else if (shelljs.which("yarn")) {
shelljs.exec("yarn");
} else {
shelljs.exec("npm install");
}
// link 到全局
shelljs.exec("npm link");
// 验证是否全局安装成功
shelljs.exec("my-vue");
npm unlink
可以解除软连接,也就是全局卸载
总结
我们介绍了如何自行开发一款 CLI 工具,这不仅对于个人来说扩展了知识面,也能很好的利用技术来提高团队协作的效率,很多事情能用脚本自动化完成的就努力的让其代替重复的人工操作,工具越积累越多,团队协作效率也会越来越高。
如果有对 CLI 功能实现细节有想法的小伙伴,欢迎在评论区讨论哦~
转载自:https://juejin.cn/post/7135445971424509983