vue.config.js 4.8 KB

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