
实现方案
根据以上思路,我先定义了属于我们项目自己的
ignore 文件,取名为
templates.ignore 。然后在这个
ignore 文件中添加需要被忽略的文件名。
{{#unless supportMacawAdmin}}
# 如果不开启admin后台,登录页面和密码修改页面是不需要的
src/entry/login.js
src/entry/password.js
{{/unless}}# 最终生成的项目中不需要ignore文字自身
templates.ignore
然后在
lib/generator.js 中添加对
templates.ignore 的处理逻辑
// ...const minimatch = require('minimatch') // https://github.com/isaacs/minimatch
module.exports = function (metadata = {}, src, dest = '.') {
if (!src) {
return Promise.reject(new Error(`无效的source:${src}`))
}
return new Promise((resolve, reject) => {
const metalsmith = Metalsmith(process.cwd())
.metadata(metadata)
.clean(false)
.source(src)
.destination(dest)
// 判断下载的项目模板中是否有templates.ignore
const ignoreFile = path.join(src, 'templates.ignore')
if (fs.existsSync(ignoreFile)) {
// 定义一个用于移除模板中被忽略文件的metalsmith插件
metalsmith.use((files, metalsmith, done) => {
const meta = metalsmith.metadata()
// 先对ignore文件进行渲染,然后按行切割ignore文件的内容,拿到被忽略清单
const ignores = Handlebars.compile(fs.readFileSync(ignoreFile).toString())(meta)
.split('n').filter(item => !!item.length)
Object.keys(files).forEach(fileName => {
// 移除被忽略的文件
ignores.forEach(ignorePattern => {
if (minimatch(fileName, ignorePattern)) {
delete files[fileName] }
})
})
done()
})
}
metalsmith.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 => {
rm(src)
err ? reject(err) : resolve()
})
})
}
基于插件思想的metalsmith很好扩展,实现也不复杂,具体过程可参见代码中的注释。
总结
经过对vue-cli的整理,借助了很多node模块,整个脚手架的实现并不复杂。
将项目模板与脚手架工具分离,可以更好的维护模板和脚手架工具。
通过commander.js处理命令行









