webpackUtils.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. const fs = require('fs')
  2. const path = require('path')
  3. const glob = require('glob')
  4. const {
  5. warn,
  6. error,
  7. info,
  8. } = require('@vue/cli-shared-utils')
  9. let pages = {}
  10. /**
  11. * 创建多页面配置信息
  12. */
  13. module.exports.getPages = function () {
  14. glob.sync('./src/pages/*/*.js').forEach(filepath => {
  15. let fileList = filepath.split('/')
  16. let module = fileList[fileList.length - 2]
  17. pages[module] = {
  18. template: `src/pages/${module}/index.html`,
  19. entry: `src/pages/${module}/main.js`,
  20. // 模板来源
  21. // 在 dist/index.html 的输出
  22. filename: process.env.NODE_ENV === 'development' ? module : `${module}/index.html`,
  23. // 提取出来的通用 chunk 和 vendor chunk。
  24. // chunks: ['chunk-vendors', 'common', module],
  25. }
  26. })
  27. return pages
  28. }
  29. let changing = false
  30. module.exports.changeProjectContext = function (newContext) {
  31. // webpack会多次编译,对重复的操作进行拒绝
  32. if (changing) {
  33. return
  34. }
  35. changing = true
  36. // 寻找admin/index.html,判断现有上下文是否与新传入的一致
  37. const adminPath = './public/admin/index.html'
  38. const content = fs.readFileSync(adminPath)
  39. const index = content.indexOf('/admin/admin-')
  40. if (index < 0) {
  41. error('平台文件异常,无法启动,请保存日志信息并联系平台组')
  42. return
  43. }
  44. // 截取50个字符,找到上下文
  45. const part = content.slice(index - 50, index).toString()
  46. const oldContext = part.split('script src=').pop()
  47. if (oldContext.length < 2) {
  48. error('未找到有效的上下文信息,无法执行工程初始化,应用可能无法正常使用')
  49. return
  50. }
  51. // 已经替换过则退出
  52. if (oldContext === newContext) {
  53. return
  54. }
  55. warn('正在执行工程初始化过程,中断可能导致工程异常无法启动!')
  56. // 所有目录下为index.html的是框架编译文件,需要进行替换
  57. glob('./public/*/index.html', (findErr, indexFiles) => {
  58. if (!findErr) {
  59. indexFiles.forEach(indexFile => {
  60. const filePathArr = indexFile.split('/')
  61. filePathArr.pop()
  62. const parentPath = filePathArr.join('/')
  63. // 特殊处理服务监控
  64. if (filePathArr[filePathArr.length - 1] !== 'service-monitor' && filePathArr[filePathArr.length - 1] !== 'sba-app' && filePathArr[filePathArr.length - 1] !== 'service-ability-monitor') {
  65. // 根据index.html找到其目录下所有文件
  66. replaceFileContentInDirectory(parentPath, oldContext, newContext)
  67. }
  68. })
  69. } else {
  70. error('获取编译文件目录失败')
  71. throw findErr
  72. }
  73. })
  74. // 替换库文件上下文
  75. const libPath = './public/common-assets/js/direwolf-library.js'
  76. replaceFileContent(libPath, oldContext, newContext)
  77. warn('工程初始化完成!')
  78. }
  79. /**
  80. * 替换目录下所有文件的指定内容
  81. * @param path
  82. * @param oldContext
  83. * @param newContext
  84. */
  85. function replaceFileContentInDirectory (path, oldContext, newContext) {
  86. glob(`${path}/*`, (error, files) => {
  87. if (!error) {
  88. files.forEach(file => {
  89. replaceFileContent(file, oldContext, newContext)
  90. })
  91. } else {
  92. error('获取编译文件目录下文件失败')
  93. throw error
  94. }
  95. })
  96. }
  97. function replaceFileContent (file, oldContext, newContext) {
  98. fs.readFile(file, 'utf8', (readErr, data) => {
  99. if (!readErr) {
  100. // 替换上下文
  101. const result = data.replace(new RegExp(oldContext, 'g'), newContext)
  102. fs.writeFile(file, result, 'utf8', function (err) {
  103. if (err) return error('替换文件内容失败', err)
  104. })
  105. } else {
  106. error('读取文件失败:' + file)
  107. throw readErr
  108. }
  109. })
  110. }
  111. module.exports.checkProjectConfig = ({ projectContext, backServerType, system }) => {
  112. info('开始检查app.config.js文件配置')
  113. if (['msa', 'soa'].indexOf(backServerType) === -1) {
  114. throw Error('后端类型选择其中之一:msa/soa')
  115. }
  116. if (!projectContext.startsWith('/') || projectContext.endsWith('/')) {
  117. throw Error(`系统上下文开头必须有斜杠,结尾必须没有斜杠,错误值:${projectContext}`)
  118. }
  119. if ((projectContext !== '/direwolf-app' && system.namespace === 'direwolf-cloud') || !system.namespace) {
  120. throw Error('请设置应用所属业务域(命名空间)的值')
  121. }
  122. info('app.config.js文件配置检查通过')
  123. }
  124. module.exports.getDirectories = source => fs.readdirSync(source)
  125. .filter(name => fs.lstatSync(path.join(source, name)).isDirectory())
  126. /**
  127. * 将自定义样式合并到common中
  128. * @param outputDir
  129. * @param assetsDir
  130. * @param pageNames
  131. */
  132. module.exports.combineStyle = (outputDir, assetsDir, pageNames) => {
  133. info('开始处理自定义样式文件')
  134. let filePath = `${outputDir}/${assetsDir}/css/`
  135. if (pageNames.length === 1) {
  136. // 只有一个页面时,只会输出一个module css文件
  137. filePath += `${pageNames[0]}/${pageNames[0]}-*.css`
  138. } else {
  139. // 否则会有公共样式文件生成
  140. filePath += `chunk/chunk-common-*.css`
  141. }
  142. // 标记后面的内容是项目自定义的
  143. const separateStartMark = '.separator-line-start-here{display:none}'
  144. const separateEndMark = '.separator-line-end-here{visibility:hidden}'
  145. glob(filePath, (findErr, cssFiles) => {
  146. if (!findErr && cssFiles.length > 0) {
  147. const content = fs.readFileSync(cssFiles[0])
  148. const index = content.indexOf(separateStartMark)
  149. const endIndex = content.indexOf(separateEndMark)
  150. if (index < 0 || endIndex < 0) {
  151. return
  152. }
  153. // 截取标记后面的内容添加到公共文件
  154. const customStyles = content.slice(index + separateStartMark.length, endIndex)
  155. // 全局样式文件
  156. const outputCssChunk = `${outputDir}/common-assets/css/chunk/`
  157. const commonCssPath = glob.sync(`${outputCssChunk}chunk-common*.css`)[0]
  158. const resultContent = fs.readFileSync(commonCssPath)
  159. const resultIndex = resultContent.indexOf(customStyles.toString())
  160. if (resultIndex !== -1) {
  161. return
  162. }
  163. info('开始合并自定义样式文件')
  164. const startBeforeIndex = resultContent.indexOf(separateStartMark)
  165. const startBefore = resultContent.slice(0, startBeforeIndex + separateStartMark.length)
  166. const endAfterIndex = resultContent.indexOf(separateEndMark)
  167. const endAfter = resultContent.slice(endAfterIndex)
  168. // 如果以截取标记结尾,表示没有添加过,否则无需重复添加
  169. fs.truncateSync(commonCssPath)
  170. fs.appendFileSync(commonCssPath, startBefore)
  171. fs.appendFileSync(commonCssPath, customStyles)
  172. fs.appendFileSync(commonCssPath, endAfter)
  173. info('开始拷贝到开发环境')
  174. fs.copyFile(commonCssPath,
  175. `${outputCssChunk}element-common.css`,
  176. (copyCommonCssErr) => {
  177. if (copyCommonCssErr) throw copyCommonCssErr
  178. })
  179. // 拷贝到public中修改原始文件
  180. const fileName = commonCssPath.split('/').pop()
  181. const publicCssChunk = `public/common-assets/css/chunk/`
  182. fs.copyFile(commonCssPath,
  183. `${publicCssChunk}${fileName}`,
  184. (copyCommonCssErr) => {
  185. if (copyCommonCssErr) throw copyCommonCssErr
  186. })
  187. // 修改名称覆盖element-common.css文件
  188. fs.copyFile(commonCssPath,
  189. `${publicCssChunk}element-common.css`,
  190. (copyCommonCssErr) => {
  191. if (copyCommonCssErr) throw copyCommonCssErr
  192. })
  193. info('自定义样式文件完成')
  194. } else {
  195. error('查找编译输出样式文件失败')
  196. throw findErr
  197. }
  198. })
  199. }