@wbi/cli-service
Version:
local service for wb-cli projects
281 lines (258 loc) • 9.49 kB
JavaScript
/**
* Created by Administrator on 2019/2/7.
* 一些辅助方法
*/
const fs = require('fs')
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const glob = require('glob')
const rm = require('rimraf')
// resolve项目根目录地址
const resolve = str => path.join(process.cwd(), str)
const wbConfig = require(resolve('./wb.config'))
const config = wbConfig.private
exports.resolve = resolve
exports.wbConfig = wbConfig
exports.privateConfig = config
// 当前cli配置文件夹地址
exports.resolveConfig = str => path.join(__dirname, '../', 'config', str)
// 获取生成模式下的的htmlPlugins
exports.getHtmlPluginsInBuildList = function () {
let htmlPlugins = []
// 模板继承扩展
if (wbConfig.extend) {
const pages = parseExtend()
createExtendPage(pages)
}
glob.sync('./src/*.pug').concat(glob.sync('./.tmp/*.pug')).forEach(file => {
let key = file.match(/\.\/(src|\.tmp)\/(.*)\.pug/)[2]
let isInWhiteList = true
if (!config.buildAll && config.buildList.length) {
isInWhiteList = config.buildList.some(function (page) {
return page === key
})
}
isInWhiteList && htmlPlugins.push(
new HtmlWebpackPlugin({
filename: key + '.html',
template: file,
multihtmlCache: true // 多页面时,用来解决热重载慢的问题
})
)
})
return htmlPlugins
}
// 获取开发模式下的的htmlPlugins
exports.getHtmlPluginsInDevList = function () {
let htmlPlugins = []
// 模板继承扩展
if (wbConfig.extend) {
const pages = parseExtend()
createExtendPage(pages)
}
glob.sync('./src/*.pug').concat(glob.sync('./.tmp/*.pug')).forEach(file => {
let key = file.match(/\.\/(src|\.tmp)\/(.*)\.pug/)[2]
let isInWhiteList = true
if (!config.devAll && config.devList.length) {
isInWhiteList = config.devList.some(function (page) {
return page === key
})
}
isInWhiteList && htmlPlugins.push(
new HtmlWebpackPlugin({
filename: key + '.html',
template: file,
multihtmlCache: true // 多页面时,用来解决热重载慢的问题
})
)
})
return htmlPlugins
}
// 解析模板继承的数据
// 解析之后会在extend数据的具体页面中增加 extendData 属性
const parseExtend = () => {
const pages = {}
Object.keys(wbConfig.extend.pages).forEach(pageName => {
const page = wbConfig.extend.pages[pageName]
let dataContent = fs.readFileSync(page.dataFile).toString()
// src路径变量解析
const srcPath = '../src/'
const staticPath = ''
const commonStaticPath = ''
// 所有站点路径变量解析
Object.keys(config.sitePath).forEach(pathKey => {
global[pathKey] = config.sitePath[pathKey]
})
eval(dataContent.replace(/.*-\r?\n/, ''))
if (!page.replace) {
page.replace = [/extendData.panels\[0\]\[0\]/g, 'extendData.panels[{index1}][{index2}]']
}
pages[pageName] = {extendData, ...page}
})
return pages
}
// 根据模板批量创建页面
// 创建的页面存放到根目录的 .tmp 文件夹下
const createExtendPage = pages => {
const tmpPath = resolve('./.tmp')
rm.sync(tmpPath)
fs.mkdirSync(tmpPath)
Object.keys(pages).forEach(pageName => {
const page = pages[pageName]
let templateContent = fs.readFileSync(page.template).toString()
page.extendData.panels.forEach((data, index1) => {
data.forEach((item, index2) => {
let targetContent = templateContent.replace('extends layouts', 'extends ../src/layouts')
let regTarget = page.replace[1].replace('{index1}', index1)
regTarget = regTarget.replace('{index2}', index2)
targetContent = targetContent.replace(page.replace[0], regTarget)
fs.writeFileSync(path.join(tmpPath, `${item.pageName}.pug`), targetContent)
})
})
})
}
// 将二维数组拍平成一维数组
const flatten = arr => [].concat( ...arr.map(x => x) )
// 获取构建配置文件
exports.getConfigFiles = function () {
return glob.sync(path.join(__dirname, './**/!(webpack.prod.config).*')).map(file => {
return path.resolve(process.cwd(), file)
}).concat([resolve('./wb.config.js'), resolve('./private.config.js')])
}
// 获取静态资源路径
exports.getStaticPath = function (opts = {}) {
let res = {}
if (process.env.NODE_ENV === 'development') {
res.staticPath = path.posix.join(opts.publicPath || wbConfig.publicPath.dev, 'static')
res.commonStaticPath = path.posix.join(opts.publicPath || wbConfig.publicPath.dev, 'commonStatic')
} else {
const publicPath = opts.publicPath || wbConfig.publicPath.build
if (publicPath.substring(0, 4) !== 'http') {
res.staticPath = path.posix.join(publicPath, 'static')
res.commonStaticPath = path.posix.join(publicPath, 'commonStatic')
} else {
res.staticPath = publicPath + 'static'
res.commonStaticPath = publicPath + 'commonStatic'
}
}
return res
}
// 解析静态资源,将{staticPath}、{commonStaticPath}替换成真实的资源路径
exports.parseStaticAssets = function (staticTemplate, staticPath, staticAssets = {}) {
Object.keys(staticAssets).forEach(key => {
const assets = staticAssets[key]
assets.forEach((file, index) => {
assets[index] = file.replace(staticTemplate, staticPath)
})
})
return staticAssets
}
// 合并静态资源
exports.mergeStaticAssets = function ({type, staticTemplate, directory, modifyName, outPath, staticAssets, hash7}) {
Object.keys(staticAssets).forEach(key => {
let content = ''
const assets = staticAssets[key] || []
assets.forEach(file => {
content += fs.readFileSync(file.replace(staticTemplate, directory)) + '\n'
})
if (assets.length) {
fs.writeFileSync(`${outPath}/${type}/lib/vendor${modifyName}${hash7 ? '.' + hash7 : ''}.${key}`, content)
}
})
}
// 修改main.scss的$staticPath路径
exports.modifyStyleStaticPath = function (staticPath, commonStaticPath) {
const mainScssFile = resolve('./src/css/main.scss')
let mainScss = fs.readFileSync(mainScssFile, 'utf8')
let staticReg = /\$staticPath\s*:\s*'(.*)'/
let commonStaticReg = /\$commonStaticPath\s*:\s*'(.*)'/
let oldStaticPath = mainScss.match(staticReg)[1]
let oldCommonStaticPath = mainScss.match(commonStaticReg)[1]
let canReWrite = false
if (oldStaticPath !== staticPath) {
mainScss = mainScss.replace(staticReg, function () {
return '$staticPath: \''+ staticPath +'\''
})
canReWrite = true
}
if (oldCommonStaticPath !== commonStaticPath) {
mainScss = mainScss.replace(commonStaticReg, function () {
return '$commonStaticPath: \''+ commonStaticPath +'\''
})
canReWrite = true
}
if (canReWrite) {
fs.writeFileSync(mainScssFile, mainScss)
}
}
// 拷贝对象
// 这里实现了深、浅拷贝
const copyObject = function () {
let i = 1,
target = arguments[0] || {},
deep = false,
length = arguments.length,
name, options, src, copy,
copyIsArray, clone;
// 如果第一个参数的数据类型是Boolean类型
// target往后取第二个参数
if (typeof target === 'boolean') {
deep = target;
// 使用||运算符,排除隐式强制类型转换为false的数据类型
// 如'', 0, undefined, null, false等
// 如果target为以上的值,则设置target = {}
target = arguments[1] || {};
i++;
}
// 如果target不是一个对象或数组或函数
if (typeof target !== 'object' && !(typeof target === 'function')) {
target = {};
}
// 如果arguments.length === 1 或
// typeof arguments[0] === 'boolean',
// 且存在arguments[1],则直接返回target对象
if (i === length) {
return target;
}
// 循环每个源对象
for (; i < length; i++) {
// 如果传入的源对象是null或undefined
// 则循环下一个源对象
if (typeof (options = arguments[i]) != null) {
// 遍历所有[[emuerable]] === true的源对象
// 包括Object, Array, String
// 如果遇到源对象的数据类型为Boolean, Number
// for in循环会被跳过,不执行for in循环
for (name in options) {
// src用于判断target对象是否存在name属性
src = target[name];
// copy用于复制
copy = options[name];
// 判断copy是否是数组
copyIsArray = Array.isArray(copy);
if (deep && copy && (typeof copy === 'object' || copyIsArray)) {
if (copyIsArray) {
copyIsArray = false;
// 如果目标对象存在name属性且是一个数组
// 则使用目标对象的name属性,否则重新创建一个数组,用于复制
clone = src && Array.isArray(src) ? src : [];
} else {
// 如果目标对象存在name属性且是一个对象
// 则使用目标对象的name属性,否则重新创建一个对象,用于复制
clone = src && typeof src === 'object' ? src : {};
}
// 深复制,所以递归调用copyObject函数
// 返回值为target对象,即clone对象
// copy是一个源对象
target[name] = copyObject(deep, clone, copy);
} else if (copy !== undefined){
// 浅复制,直接复制到target对象上
target[name] = copy;
}
}
}
}
// 返回目标对象
return target;
}
exports.copyObject = copyObject