UNPKG

vincent-cli

Version:

基于vue全家桶的脚手架,主要包含webapp、一般网页的模板。

164 lines (145 loc) 4.39 kB
const chalk = require('chalk') const Metalsmith = require('metalsmith') // 能力高效地容易地创立语义化的模版 const Handlebars = require('handlebars') // 模板引擎库 const async = require('async') const render = require('consolidate').handlebars.render // 模板引擎整合库 const path = require('path') const multimatch = require('multimatch') // 正则表达式扩展 const getOptions = require('./options') const ask = require('./ask') const filter = require('./filter') const logger = require('./logger') // 注册handlebars helper Handlebars.registerHelper('if_eq', function (a, b, opts) { return a === b ? opts.fn(this) : opts.inverse(this) }) Handlebars.registerHelper('unless_eq', function (a, b, opts) { return a === b ? opts.inverse(this) : opts.fn(this) }) /** * 生成模板。得到src和dest * * @param {String} name * @param {String} src * @param {String} dest * @param {Function} done */ module.exports = function generate (name, src, dest, done) { const opts = getOptions(name, src) const metalsmith = Metalsmith(path.join(src, 'template')) const data = Object.assign(metalsmith.metadata(), { destDirName: name, inPlace: dest === process.cwd(), noEscape: true }) // 注册模板中自定义的语法 opts.helpers && Object.keys(opts.helpers).map(key => { Handlebars.registerHelper(key, opts.helpers[key]) }) const helpers = { chalk, logger } // 渲染模板之前的钩子 if (opts.metalsmith && typeof opts.metalsmith.before === 'function') { opts.metalsmith.before(metalsmith, opts, helpers) } // 提问 -> 过滤 -> 渲染模板文件 metalsmith.use(askQuestions(opts.prompts)) .use(filterFiles(opts.filters)) .use(renderTemplateFiles(opts.skipInterpolation)) // 渲染完成的钩子 if (typeof opts.metalsmith === 'function') { opts.metalsmith(metalsmith, opts, helpers) } else if (opts.metalsmith && typeof opts.metalsmith.after === 'function') { opts.metalsmith.after(metalsmith, opts, helpers) } metalsmith.clean(false) .source('.') // start from template root instead of `./src` which is Metalsmith's default for `source` .destination(dest) .build((err, files) => { // 渲染完成回调 done(err) if (typeof opts.complete === 'function') { const helpers = { chalk, logger, files } opts.complete(data, helpers) } else { logMessage(opts.completeMessage, data) } }) return data } /** * 发起问题中间件 * * @param {Object} prompts * @return {Function} */ function askQuestions (prompts) { return (files, metalsmith, done) => { ask(prompts, metalsmith.metadata(), done) } } /** * 文件过滤中间件 * * @param {Object} filters * @return {Function} */ function filterFiles (filters) { return (files, metalsmith, done) => { filter(files, filters, metalsmith.metadata(), done) } } /** * 模板渲染 * * @param {Object} files * @param {Metalsmith} metalsmith * @param {Function} done */ function renderTemplateFiles (skipInterpolation) { skipInterpolation = typeof skipInterpolation === 'string' ? [skipInterpolation] : skipInterpolation return (files, metalsmith, done) => { const keys = Object.keys(files) const metalsmithMetadata = metalsmith.metadata() async.each(keys, (file, next) => { // 跳过Skip插值选项文件 if (skipInterpolation && multimatch([file], skipInterpolation, { dot: true }).length) { return next() } const str = files[file].contents.toString() // 不渲染没有mustaches的文件 if (!/{{([^{}]+)}}/g.test(str)) { return next() } render(str, metalsmithMetadata, (err, res) => { if (err) { err.message = `[${file}] ${err.message}` return next(err) } files[file].contents = new Buffer(res) next() }) }, done) } } /** * 显示模板渲染时的一些信息 * * @param {String} message * @param {Object} data */ function logMessage (message, data) { if (!message) return render(message, data, (err, res) => { if (err) { console.error('\n Error when rendering template complete message: ' + err.message.trim()) } else { console.log('\n' + res.split(/\r?\n/g).map(line => ' ' + line).join('\n')) } }) }