vue.config.js 4.9 KB

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