前言
我在公司的业务主要有三种:
- 管理后台,页面结构基本不变,模块可重复使用。
- webApp,页面的交互较复杂,要根据设计深度定制。
- 简单页面,一般是配合native app 使用的页面,例如活动页面,简单的内容介绍页面,交互少,开发周期短。
业务上基本形成了稳定的套路,这时候开发一套自己的脚手架工具是必要的
- 减少重复性工作,提高开发效率。
- 给不同的业务创建不同的模版,容易迭代和维护。
一方面是为了业务需要,一方面是为了练手,决定仿照vue-cli写一个脚手架工具。
思路
vue-cli 整体思路:
- 将脚手架和各个模板独立发布到Git上。
- 通过脚手架下载模版。
- 通过与脚手架的交互信息,渲染模版,得到项目基本结构。
阅读vue-cli的代码,代码思路如下:
vue
命令会执行package.json
下的bin
中指定的文件,也就是bin/vue
。这个文件中主要用到commander
这个包,这个包可以用来设置不同的命令。vue init
执行bin/vue-init
。vue init
根据你输入的官方模版或者远程仓库中的模板名下载模版,用到的包是download-git-repo
。- 仓库中有
template
目录,这里面是模版,有meta.js
或者meta.json
文件,里面的是配置内容,会被inquirer
这个包使用,进行交互式问答,后面根据问答结果渲染模版。 metalsmith
这个包根据问答内容渲染模版,这里还用到了模版引擎handlers
。
远程仓库工程结构
1 | /template # ------ 模版 |
脚手架工程结构
1 | /bin # ------ 命令执行文件 |
commander
nodejs内置了对命令行操作的支持,node工程下package.json中的bin字段可以定义命令名和关联的执行文件。
1 | { |
经过这样配置的nodejs项目,在使用-g选项进行全局安装的时候,会自动在系统的[prefix]/bin
目录下创建相应的符号链接(symlink)关联到执行文件。如果是本地安装,这个符号链接会生成在./node_modules/.bin
目录下。这样做的好处是可以直接在终端中像执行命令一样执行nodejs文件。关于prefix
,可以通过npm config get prefix
获取。
定义命令
在bin目录下创建一个hxlz.js文件,用于处理命令行的逻辑。
1 |
|
定义子命令
ommander支持git风格的子命令处理,可以根据子命令自动引导到以特定格式命名的命令执行文件,文件名的格式是[command]-[subcommand]
,例如:
hxlz init => hxlz-init
在bin目录下创建一个hxlz-init.js文件
1 |
|
使用download-git-repo下载模板
新建lib/download.js
文件,用于下载模版
1 | const download = require('download-git-repo') |
使用Promise的风格处理异步
对hxlz-init.js
进行修改
1 | const download = require('./lib/download') |
处理远程仓库中的meta.json文件,使用inquirer.js处理命令行交互
这里直接使用了vue-cli的ask.js
文件
使用metalsmith处理模板
这里还用到了模版引擎handlebars
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26const Metalsmith = require('metalsmith')
const Handlebars = require('handlebars')
module.exports = function (metadata = {}, src, dest = '.') {
if (!src) {
return Promise.reject(new Error(`无效的source:${src}`))
}
return new Promise((resolve, reject) => {
Metalsmith(process.cwd())
.metadata(metadata)
.clean(false)
.source(src)
.destination(dest)
.use((files, metalsmith, done) => {
const meta = metalsmith.metadata()
Object.keys(files).forEach(fileName => {
const t = files[fileName].contents.toString()
files[fileName].contents = new Buffer(Handlebars.compile(t)(meta))
})
done()
}).build(err => {
err ? reject(err) : resolve()
})
})
}
美化脚手架
通过一些工具包,让脚手架更加人性化。这里介绍两个在vue-cli中发现的工具包:
- ora - 显示spinner
- chalk - 给枯燥的终端界面添加一些色彩
参考链接