const fs = require('fs') const path = require('path') const glob = require('glob') const { warn, error, info, } = require('@vue/cli-shared-utils') let pages = {} /** * 创建多页面配置信息 */ module.exports.getPages = function () { glob.sync('./src/pages/*/*.js').forEach(filepath => { let fileList = filepath.split('/') let module = fileList[fileList.length - 2] pages[module] = { template: `src/pages/${module}/index.html`, entry: `src/pages/${module}/main.js`, // 模板来源 // 在 dist/index.html 的输出 filename: process.env.NODE_ENV === 'development' ? module : `${module}/index.html`, // 提取出来的通用 chunk 和 vendor chunk。 // chunks: ['chunk-vendors', 'common', module], } }) return pages } let changing = false module.exports.changeProjectContext = function (newContext) { // webpack会多次编译,对重复的操作进行拒绝 if (changing) { return } changing = true // 寻找admin/index.html,判断现有上下文是否与新传入的一致 const adminPath = './public/admin/index.html' const content = fs.readFileSync(adminPath) const index = content.indexOf('/admin/admin-') if (index < 0) { error('平台文件异常,无法启动,请保存日志信息并联系平台组') return } // 截取50个字符,找到上下文 const part = content.slice(index - 50, index).toString() const oldContext = part.split('script src=').pop() if (oldContext.length < 2) { error('未找到有效的上下文信息,无法执行工程初始化,应用可能无法正常使用') return } // 已经替换过则退出 if (oldContext === newContext) { return } warn('正在执行工程初始化过程,中断可能导致工程异常无法启动!') // 所有目录下为index.html的是框架编译文件,需要进行替换 glob('./public/*/index.html', (findErr, indexFiles) => { if (!findErr) { indexFiles.forEach(indexFile => { const filePathArr = indexFile.split('/') filePathArr.pop() const parentPath = filePathArr.join('/') // 特殊处理服务监控 if (filePathArr[filePathArr.length - 1] !== 'service-monitor' && filePathArr[filePathArr.length - 1] !== 'sba-app' && filePathArr[filePathArr.length - 1] !== 'service-ability-monitor') { // 根据index.html找到其目录下所有文件 replaceFileContentInDirectory(parentPath, oldContext, newContext) } }) } else { error('获取编译文件目录失败') throw findErr } }) // 替换库文件上下文 const libPath = './public/common-assets/js/direwolf-library.js' replaceFileContent(libPath, oldContext, newContext) warn('工程初始化完成!') } /** * 替换目录下所有文件的指定内容 * @param path * @param oldContext * @param newContext */ function replaceFileContentInDirectory (path, oldContext, newContext) { glob(`${path}/*`, (error, files) => { if (!error) { files.forEach(file => { replaceFileContent(file, oldContext, newContext) }) } else { error('获取编译文件目录下文件失败') throw error } }) } function replaceFileContent (file, oldContext, newContext) { fs.readFile(file, 'utf8', (readErr, data) => { if (!readErr) { // 替换上下文 const result = data.replace(new RegExp(oldContext, 'g'), newContext) fs.writeFile(file, result, 'utf8', function (err) { if (err) return error('替换文件内容失败', err) }) } else { error('读取文件失败:' + file) throw readErr } }) } module.exports.checkProjectConfig = ({ projectContext, backServerType, system }) => { info('开始检查app.config.js文件配置') if (['msa', 'soa'].indexOf(backServerType) === -1) { throw Error('后端类型选择其中之一:msa/soa') } if (!projectContext.startsWith('/') || projectContext.endsWith('/')) { throw Error(`系统上下文开头必须有斜杠,结尾必须没有斜杠,错误值:${projectContext}`) } if ((projectContext !== '/direwolf-app' && system.namespace === 'direwolf-cloud') || !system.namespace) { throw Error('请设置应用所属业务域(命名空间)的值') } info('app.config.js文件配置检查通过') } module.exports.getDirectories = source => fs.readdirSync(source) .filter(name => fs.lstatSync(path.join(source, name)).isDirectory()) /** * 将自定义样式合并到common中 * @param outputDir * @param assetsDir * @param pageNames */ module.exports.combineStyle = (outputDir, assetsDir, pageNames) => { info('开始处理自定义样式文件') let filePath = `${outputDir}/${assetsDir}/css/` if (pageNames.length === 1) { // 只有一个页面时,只会输出一个module css文件 filePath += `${pageNames[0]}/${pageNames[0]}-*.css` } else { // 否则会有公共样式文件生成 filePath += `chunk/chunk-common-*.css` } // 标记后面的内容是项目自定义的 const separateStartMark = '.separator-line-start-here{display:none}' const separateEndMark = '.separator-line-end-here{visibility:hidden}' glob(filePath, (findErr, cssFiles) => { if (!findErr && cssFiles.length > 0) { const content = fs.readFileSync(cssFiles[0]) const index = content.indexOf(separateStartMark) const endIndex = content.indexOf(separateEndMark) if (index < 0 || endIndex < 0) { return } // 截取标记后面的内容添加到公共文件 const customStyles = content.slice(index + separateStartMark.length, endIndex) // 全局样式文件 const outputCssChunk = `${outputDir}/common-assets/css/chunk/` const commonCssPath = glob.sync(`${outputCssChunk}chunk-common*.css`)[0] const resultContent = fs.readFileSync(commonCssPath) const resultIndex = resultContent.indexOf(customStyles.toString()) if (resultIndex !== -1) { return } info('开始合并自定义样式文件') const startBeforeIndex = resultContent.indexOf(separateStartMark) const startBefore = resultContent.slice(0, startBeforeIndex + separateStartMark.length) const endAfterIndex = resultContent.indexOf(separateEndMark) const endAfter = resultContent.slice(endAfterIndex) // 如果以截取标记结尾,表示没有添加过,否则无需重复添加 fs.truncateSync(commonCssPath) fs.appendFileSync(commonCssPath, startBefore) fs.appendFileSync(commonCssPath, customStyles) fs.appendFileSync(commonCssPath, endAfter) info('开始拷贝到开发环境') fs.copyFile(commonCssPath, `${outputCssChunk}element-common.css`, (copyCommonCssErr) => { if (copyCommonCssErr) throw copyCommonCssErr }) // 拷贝到public中修改原始文件 const fileName = commonCssPath.split('/').pop() const publicCssChunk = `public/common-assets/css/chunk/` fs.copyFile(commonCssPath, `${publicCssChunk}${fileName}`, (copyCommonCssErr) => { if (copyCommonCssErr) throw copyCommonCssErr }) // 修改名称覆盖element-common.css文件 fs.copyFile(commonCssPath, `${publicCssChunk}element-common.css`, (copyCommonCssErr) => { if (copyCommonCssErr) throw copyCommonCssErr }) info('自定义样式文件完成') } else { error('查找编译输出样式文件失败') throw findErr } }) }