vue.config.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. const { defineConfig } = require('@vue/cli-service');
  2. const webpack = require('webpack');
  3. const path = require('path');
  4. const config = require('./config');
  5. const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
  6. const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
  7. const AutoImport = require('unplugin-auto-import/webpack');
  8. const Components = require('unplugin-vue-components/webpack');
  9. const { ElementPlusResolver } = require('unplugin-vue-components/resolvers');
  10. const IS_PRODUCTION = process.env.NODE_ENV === 'production';
  11. // 当前场景
  12. const SCENE = process.env.SCENE;
  13. if (SCENE != null) {
  14. console.log('当前场景:', SCENE);
  15. }
  16. const ENV = getEnv();
  17. module.exports = defineConfig({
  18. publicPath: './',
  19. transpileDependencies: true,
  20. lintOnSave: false,
  21. indexPath: `${SCENE || 'index'}.html`,
  22. // outputDir: IS_PRODUCTION && !!SCENE ? `build/${SCENE}` : 'build',
  23. // 根据场景隔离
  24. // assetsDir: path.posix.join(config.assetsDir, SCENE || ''),
  25. productionSourceMap: process.env.SOURCE_MAP === 'true' || false,
  26. css: {
  27. loaderOptions: {
  28. sass: {
  29. additionalData: ENV.sass,
  30. },
  31. },
  32. },
  33. /**
  34. * 开发服务器配置
  35. */
  36. devServer: {
  37. compress: true,
  38. host: '0.0.0.0',
  39. port: process.env.PORT || 80,
  40. historyApiFallback: true,
  41. allowedHosts: 'all',
  42. },
  43. configureWebpack: {
  44. devtool: 'source-map',
  45. resolve: {
  46. symlinks: false,
  47. alias: {
  48. '@': path.join(__dirname, 'src'),
  49. },
  50. },
  51. plugins: [
  52. new NodePolyfillPlugin(),
  53. // 扩展 process.env
  54. new webpack.DefinePlugin(ENV.define),
  55. AutoImport({
  56. resolvers: [ElementPlusResolver()],
  57. }),
  58. Components({
  59. resolvers: [ElementPlusResolver()],
  60. }),
  61. ],
  62. },
  63. chainWebpack: (webpackConfig) => {
  64. if (SCENE != null) {
  65. const extensions = webpackConfig.resolve.extensions.values();
  66. for (let i = extensions.length - 1; i >= 0; i--) {
  67. webpackConfig.resolve.extensions.prepend(`.${SCENE}${extensions[i]}`);
  68. }
  69. }
  70. webpackConfig.module
  71. .rule('json')
  72. .test(/(.*)\.tr$/)
  73. .use('json-loader')
  74. .loader('json-loader')
  75. .end();
  76. if (IS_PRODUCTION) {
  77. webpackConfig.plugin('loadshReplace').use(new LodashModuleReplacementPlugin());
  78. // 主包分割
  79. webpackConfig.optimization.splitChunks({
  80. cacheGroups: {
  81. common: {
  82. name: 'chunk-common',
  83. chunks: 'initial',
  84. minChunks: 2,
  85. // 一个入口最大的并行请求数
  86. maxInitialRequests: 4,
  87. // 形成一个新代码块最小的体积
  88. minSize: 5000,
  89. // 缓存组打包的先后优先级
  90. priority: 1,
  91. // 如果当前的 chunk 已被从 split 出来,那么将会直接复用这个 chunk 而不是重新创建一个
  92. reuseExistingChunk: true,
  93. },
  94. vendors: {
  95. name: 'chunk-vendors',
  96. test: /[\\/]node_modules[\\/]/,
  97. chunks: 'initial',
  98. priority: 2,
  99. reuseExistingChunk: true,
  100. // 总是为这个缓存组创建 chunks
  101. enforce: true,
  102. },
  103. elementIcons: {
  104. name: 'element-icons',
  105. test: /[\\/]node_modules[\\/]@element-plus[\\/]/,
  106. chunks: 'initial',
  107. priority: 3,
  108. reuseExistingChunk: true,
  109. enforce: true,
  110. },
  111. elementPlus: {
  112. name: 'element-plus',
  113. test: /[\\/]node_modules[\\/]element-plus[\\/]/,
  114. chunks: 'initial',
  115. priority: 3,
  116. reuseExistingChunk: true,
  117. enforce: true,
  118. },
  119. },
  120. });
  121. }
  122. webpackConfig.plugin('html').tap((args) => {
  123. args[0].title = process.env.TITLE;
  124. return args;
  125. });
  126. },
  127. });
  128. /**
  129. * 初始化环境变量
  130. */
  131. function getEnv() {
  132. const constants = config.constants;
  133. // 扩展内置变量
  134. for (const key in constants) {
  135. process.env[`VUE_APP_${key}`] = constants[key];
  136. }
  137. // 内置变量
  138. const vueVariables = ['NODE_ENV', 'BASE_URL'];
  139. const variableNames = [...vueVariables, 'SCENE', 'HOT_DOMAIN'];
  140. const variables = [];
  141. for (const key in process.env) {
  142. if (key.startsWith('VUE_APP_')) {
  143. variableNames.push(key);
  144. }
  145. }
  146. variableNames.forEach((name) => {
  147. variables.push(`${name}: "${process.env[name]}"`);
  148. });
  149. return {
  150. sass: variables.map((d) => `$` + d + ';\n').join(''),
  151. variableNames,
  152. variables,
  153. // 用于 definePlugin
  154. define: variableNames
  155. .filter((name) => {
  156. return !name.startsWith('VUE_APP_') && !vueVariables.includes(name);
  157. })
  158. .reduce((prev, cur) => {
  159. prev[`process.env.${cur}`] = JSON.stringify(process.env[cur]);
  160. return prev;
  161. }, {}),
  162. };
  163. }