vue.config.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /* eslint-disable filenames/match-regex */
  2. const path = require('path')
  3. const webpack = require('webpack')
  4. const AliasPlugin = require('enhanced-resolve/lib/AliasPlugin')
  5. const CircularDependencyPlugin = require('circular-dependency-plugin')
  6. const { argv } = require('yargs')
  7. const openInEditor = require('launch-editor-middleware')
  8. const designVariables = require('./src/common/design/variables.js')
  9. function isInSrc(context) {
  10. // 判断当前上下文是否属于src目录
  11. const srcPath = path.resolve(__dirname, 'src')
  12. return context === srcPath || context.startsWith(srcPath + path.sep)
  13. }
  14. const replaceRelative = new webpack.NormalModuleReplacementPlugin(/^\..*/, function(resource) {
  15. // 将相对路径改写为完整路径,便于在custom和src目录搜索
  16. const requstFullPath = path.resolve(resource.context, resource.request)
  17. // 不是src目录发起的 或 不是引用src目录的文件,退出
  18. // 比如请求node_module下的文件时,不处理
  19. if (!isInSrc(resource.context) || !isInSrc(requstFullPath)) return
  20. let p = path.resolve(resource.context, resource.request).replace(__dirname, '')
  21. p = p.replace(/\\/g, '/').replace('/src/', '')
  22. // console.warn('\nReplace path:', resource.request, p)
  23. resource.request = p
  24. })
  25. const replaceAtSign = new webpack.NormalModuleReplacementPlugin(/^@.*/, function(resource) {
  26. // 将@开始的路径改写为完整路径,便于在custom和src目录搜索
  27. if (!isInSrc(resource.context)) return
  28. const p = resource.request.replace('@/', '')
  29. // console.warn('\n@Replace path:', resource.request, p)
  30. resource.request = p
  31. })
  32. let appConfigCustom
  33. try {
  34. appConfigCustom = require('./src_custom/app-config.js')
  35. } catch (e) {
  36. appConfigCustom = {}
  37. }
  38. const appConfig = appConfigCustom
  39. // 各种API地址,转发到后台服务器
  40. const proxy = {}
  41. const proxySetting = {
  42. target: appConfig.apiEndpoint || 'https://192.168.2.177:8898/xcoa',
  43. secure: false,
  44. changeOrigin: true,
  45. // 转发时去掉虚拟的路径
  46. pathRewrite: { '^/-app-': '' },
  47. logLevel: 'debug',
  48. }
  49. const paths = ['api', 'docviewer-webapp', ...(appConfig.apiPaths || [])]
  50. paths.forEach((path) => {
  51. proxy['/-app-/' + path] = proxySetting
  52. })
  53. process.env.VUE_APP_TITLE = appConfig.appTitle || 'GRC.Platform'
  54. module.exports = {
  55. publicPath: '',
  56. transpileDependencies: [
  57. 'ant-design-vue',
  58. 'vue-echarts',
  59. 'resize-detector',
  60. 'signature_pad',
  61. 'sm-crypto',
  62. ],
  63. devServer: {
  64. // 本地的开发服务器也加一个app路径,模拟真实环境
  65. // 注意访问的时候要加上这个虚拟路径,如:http://localhost:8080/-app-/
  66. publicPath: '/-app-/',
  67. port: appConfig.devServerPort || 8080,
  68. proxy,
  69. // 处理mock数据
  70. before(app) {
  71. app.use('/__open-in-editor', openInEditor('code'))
  72. require('./src/_mock').getBeforeHook(app)
  73. },
  74. // 允许通过域名访问
  75. disableHostCheck: true,
  76. // 静态资源存放的目录,如indidoc安装文件
  77. contentBase: [path.join(__dirname, 'src_custom', 'www')],
  78. contentBasePublicPath: '/-app-',
  79. },
  80. configureWebpack: (config) => {
  81. // sass处理器会把\xxxx转义的字符,转义回中文。用css-unicode-loader再次转成\xxxx
  82. const sassLoader = require.resolve('sass-loader')
  83. config.module.rules
  84. .filter((rule) => {
  85. if (!rule.test) return false
  86. return rule.test.toString().indexOf('scss') !== -1
  87. })
  88. .forEach((rule) => {
  89. rule.oneOf.forEach((oneOfRule) => {
  90. const sassLoaderIndex = oneOfRule.use.findIndex((item) => item.loader === sassLoader)
  91. oneOfRule.use.splice(sassLoaderIndex, 0, {
  92. loader: require.resolve('css-unicode-loader'),
  93. })
  94. })
  95. })
  96. const plugins = [
  97. replaceRelative,
  98. replaceAtSign,
  99. new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/),
  100. ]
  101. if (argv.analyseCircularDependency) {
  102. plugins.push(
  103. new CircularDependencyPlugin({
  104. exclude: /node_modules/,
  105. include: /src/,
  106. failOnError: true,
  107. allowAsyncCycles: false,
  108. cwd: process.cwd(),
  109. })
  110. )
  111. }
  112. return {
  113. plugins,
  114. resolve: {
  115. plugins: [
  116. new AliasPlugin(
  117. 'described-resolve',
  118. [
  119. {
  120. name: '@extension-points',
  121. alias: [
  122. path.resolve('src_custom', '_extension-points'),
  123. path.resolve('src', '_extension-points'),
  124. ],
  125. },
  126. ],
  127. 'resolve'
  128. ),
  129. ],
  130. },
  131. }
  132. },
  133. /**
  134. * @param {import('webpack-chain')} config
  135. */
  136. chainWebpack: (config) => {
  137. config.resolve.alias
  138. .set('@custom', path.resolve('src_custom'))
  139. .set('@product', path.resolve('src_product'))
  140. .set('@external', path.resolve('lib-external'))
  141. // 把项目定制目录放在平台目录前面,可以覆盖
  142. config.resolve.modules.add(path.resolve(__dirname, 'src_custom/_override'))
  143. config.resolve.modules.add(path.resolve(__dirname, 'src'))
  144. config.plugin('html').tap((args) => {
  145. args[0].title = process.env.VUE_APP_TITLE
  146. args[0].primaryColor = designVariables['primary-color']
  147. return args
  148. })
  149. // 避免moment被打包多次的问题
  150. config.resolve.alias.set('moment$', path.resolve(__dirname, 'node_modules/moment/moment.js'))
  151. if ((process.env.NODE_ENV === 'production' && !argv.enableSourceMap) || argv.disableSourceMap) {
  152. config.devtool('(none)')
  153. }
  154. config.plugins.delete('prefetch')
  155. config.plugins.delete('preload')
  156. },
  157. css: {
  158. requireModuleExtension: true,
  159. loaderOptions: {
  160. css: {
  161. // js中可以使用camelCase获取classname
  162. localsConvention: 'camelCase',
  163. modules: {
  164. // css moudule 生成的class规则:原class+组件名+模块名
  165. localIdentName: '[local]_[name]_[1]',
  166. localIdentRegExp: /src.([a-z-]*)/i,
  167. },
  168. },
  169. less: {
  170. modifyVars: designVariables,
  171. javascriptEnabled: true,
  172. },
  173. },
  174. },
  175. }