前言
相关技术栈和依赖
- javascript
- 发布 npm 包。
- commander 包的使用
- download-git-repo 包的使用
分析
脚手架 vue-cli
相信大家都使用过,很便捷。
# 全局安装 vue cli 包
npm install -g @vue/cli-service-global
# 使用vue cli 内置指令创建一个工程
vue create hello-world
# 运行项目
cd hello-world
npm i
npm run dev
几个指令就搭建好一个前端工程。
这边文章目的是教会大家如何发布个人的脚手架。
主要步骤如下:
- 部署自己的 npm 包
- 全局安装自己所部署的包后,要支持使用我们自定义的指令
- 配置好一个前端工程,并推送到git代码库
- 根据指令触发,拉取代码仓库到本地
发布 npm 包,支持使用指令
没有发布 npm 包经验的同学看这里:发布 npm 包
发布的包如何像以下这样,支持使用指令?
vue create hello-world
第一步:指令配置
在包的 package.json 文件增加以下指令配置
// package.json
{
...
"bin": {
"wfj-cli": "./index.js"
},
...
}
bin
属性用于配置指令,指令由 key
和 value
组成,key
为指令名,vaule
为运行指令后要执行的文件。
第二步:修改要执行的文件
index.js
#!/usr/bin/env node
console.log('hello world')
可以看到在 index.js
的首行为 #!/usr/bin/env node
。
该行作用为:使用系统下的 env 文件找到 node 安装位置,并使用 node 执行该文件。
第三步:重新部署并全局安装使用
重新部署 npm 包后,需全局安装我们部署的包,因为要使用指令必须得全局安装。
npm i -g packName
使用指令
# 执行以下指令,相当于执行了 node index.js
wfj-cli
# 执行结果
hello world
到这里,我们已经成功发布一个支持使用简单指令的 npm 包了,它只能根据指令去执行对应的文件。
如何处理更复杂的指令?
- 像 vue cli 这样,接收到指令上的参数
'hello-world'
作为创建文件夹的名称
vue create hello-world
让我们接着往下走。
commander 包的使用
commander
是一个 npm 包,是完整的 node.js 命令行解决方案。
使用 commander
可以完美解决接收指令参数、设置多个子指令等问题。
想快速上手使用,可以看我整理的使用概览:commander包使用说明
想更深入的学习请前往:官方使用说明
这边只介绍搭建脚手架需要用到的部分
继续修改上文的 index.js
文件
#!/usr/bin/env node
const { program } = require('commander')
// 设置指令版本
program.version('0.0.1')
program
// 增加指令
.command('init')
// 设置指令参数
.arguments('<filderName>')
// 指令的描述
.description('初始化 wfj-cli 脚手架')
// 执行指令的回调
.action((filderName) => {
console.log(filderName)
})
// 该行放置末尾,解析option方法所构建的参数
program.parse(process.argv)
我们使用 command
方法添加了 init
指令,以及接受 filderName
参数,并在执行指令回调函数中打印 filderName
参数。
本地运行测试
node index.js init hello-world
# 执行结果
hello-world
这样一来,我们就可以获取到指令上的参数 hello-world 了
重新部署 npm 包,并更新本地包后运行
# 更新本地包
npm update -g packName
# 执行
wfj-cli init hello-world
# 执行结果
hello-world
到这里,我们的包可以接收到指令上的参数了。
拉取代码仓库到本地
使用 download-git-repo
包可以将代码仓库 clone 到本地。
var download = require('download-git-repo');
/**
* 第一个参数:[github/gitlab]:[账户名]/[仓库名]
* 第二个参数:下载后存放路径
* 第三个参数:响应回调
*/
download('github:wenfujie/wenfujie.github.io', 'test/tmp', function (err) {
console.log(err ? err : 'Success')
})
用法相对简单,需注意的是:
- 第一个参数格式是
[github/gitlab]:[账户名]/[仓库名]
。 - 第二个参数是下载存放路径,我们只需将该值设置为上文取到的指令参数,即可达到自定义工程名称的目的。
继续修改 index.js
#!/usr/bin/env node
// 上一行作用:使用env来找到node,并使用node来作为程序的解释程序
// 异步方式转化为promise形式
const { promisify } = require('util')
// 显示进程进度
const ora = require('ora')
const { program } = require('commander')
const downloadGitRepo = require('download-git-repo')
// clone 的仓库
const REPO_DESC = 'github:wenfujie/search-360-bd'
// 主入口
function main() {
const cb = (filderName) => {
clone(REPO_DESC, filderName)
}
registerCommand(cb)
}
main()
/**
* 注册指令
* @param {function} callback 执行指令的回调函数
*/
function registerCommand(callback) {
program.version('0.0.1')
program
.command('init')
.arguments('<filderName>')
.description('脚手架初始化的描述')
.action((filderName) => {
typeof callback && callback(filderName)
})
program.parse(process.argv)
}
/**
* 下载git仓库代码
* @param {string} repo git仓库地址
* @param {string} repo 下载要存放目录
*/
async function clone(repo, desc) {
const down = promisify(downloadGitRepo)
const downProgress = ora(`下载${repo}中...`)
await down(repo, desc)
.then((res) => {
downProgress.succeed('下载成功')
})
.catch((err) => {
downProgress.failed()
})
}
这里用到一个 node 工具 promisify,作用是将异步回调的方法编译为支持 Promise 形式使用。
重新部署并更新本地包
# 更新本地包
npm update -g packName
# 执行
wfj-cli init hello-world
# 执行成功后,会在本地生成 hello-world 文件夹,并将 git 仓库克隆到文件夹下
到这里,我们就搭建了一个简版脚手架。
结尾
- 我们可以配置不同的子指令,或者参数控制,来下载不同的 git 仓库,或者控制是否初始化 vuex 、router等模块。
- 脚手架的核心观念其实是复用,这跟模块化开发思想类似。
- 搭建脚手架,能在要创建新工程时,快速的搭建好开发环境,而不是拷贝工程再去删除不需要文件和修改冗余代码。开发过程中会有很多重复性工作,比如自动化部署,尽量使用工具来释放我们双手提高开发效率。
本文涉及到相关知识点
我的其他文章