vue.config.js 5.3 KB

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