webpack.prod.conf.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. 'use strict'
  2. const path = require('path')
  3. const utils = require('./utils')
  4. const webpack = require('webpack')
  5. const config = require('../config')
  6. const merge = require('webpack-merge')
  7. const baseWebpackConfig = require('./webpack.base.conf')
  8. const CopyWebpackPlugin = require('copy-webpack-plugin')
  9. const HtmlWebpackPlugin = require('html-webpack-plugin')
  10. const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')
  11. const MiniCssExtractPlugin = require('mini-css-extract-plugin')
  12. const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
  13. const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
  14. function resolve(dir) {
  15. return path.join(__dirname, '..', dir)
  16. }
  17. const env = require('../config/' + process.env.env_config + '.env')
  18. // For NamedChunksPlugin
  19. const seen = new Set()
  20. const nameLength = 4
  21. const webpackConfig = merge(baseWebpackConfig, {
  22. mode: 'production',
  23. module: {
  24. rules: utils.styleLoaders({
  25. sourceMap: config.build.productionSourceMap,
  26. extract: true,
  27. usePostCSS: true
  28. })
  29. },
  30. devtool: config.build.productionSourceMap ? config.build.devtool : false,
  31. output: {
  32. path: config.build.assetsRoot,
  33. filename: utils.assetsPath('js/[name].[chunkhash:8].js'),
  34. chunkFilename: utils.assetsPath('js/[name].[chunkhash:8].js')
  35. },
  36. plugins: [
  37. // http://vuejs.github.io/vue-loader/en/workflow/production.html
  38. new webpack.DefinePlugin({
  39. 'process.env': env
  40. }),
  41. // extract css into its own file
  42. new MiniCssExtractPlugin({
  43. filename: utils.assetsPath('css/[name].[contenthash:8].css'),
  44. chunkFilename: utils.assetsPath('css/[name].[contenthash:8].css')
  45. }),
  46. // generate dist index.html with correct asset hash for caching.
  47. // you can customize output by editing /index.html
  48. // see https://github.com/ampedandwired/html-webpack-plugin
  49. new HtmlWebpackPlugin({
  50. filename: config.build.index,
  51. template: 'index.html',
  52. inject: true,
  53. favicon: resolve('favicon.ico'),
  54. title: 'vue-element-admin',
  55. templateParameters: {
  56. BASE_URL: config.build.assetsPublicPath + config.build.assetsSubDirectory,
  57. },
  58. minify: {
  59. removeComments: true,
  60. collapseWhitespace: true,
  61. removeAttributeQuotes: true
  62. // more options:
  63. // https://github.com/kangax/html-minifier#options-quick-reference
  64. }
  65. // default sort mode uses toposort which cannot handle cyclic deps
  66. // in certain cases, and in webpack 4, chunk order in HTML doesn't
  67. // matter anyway
  68. }),
  69. new ScriptExtHtmlWebpackPlugin({
  70. //`runtime` must same as runtimeChunk name. default is `runtime`
  71. inline: /runtime\..*\.js$/
  72. }),
  73. // keep chunk.id stable when chunk has no name
  74. new webpack.NamedChunksPlugin(chunk => {
  75. if (chunk.name) {
  76. return chunk.name
  77. }
  78. const modules = Array.from(chunk.modulesIterable)
  79. if (modules.length > 1) {
  80. const hash = require('hash-sum')
  81. const joinedHash = hash(modules.map(m => m.id).join('_'))
  82. let len = nameLength
  83. while (seen.has(joinedHash.substr(0, len))) len++
  84. seen.add(joinedHash.substr(0, len))
  85. return `chunk-${joinedHash.substr(0, len)}`
  86. } else {
  87. return modules[0].id
  88. }
  89. }),
  90. // keep module.id stable when vender modules does not change
  91. new webpack.HashedModuleIdsPlugin(),
  92. // copy custom static assets
  93. new CopyWebpackPlugin([
  94. {
  95. from: path.resolve(__dirname, '../static'),
  96. to: config.build.assetsSubDirectory,
  97. ignore: ['.*']
  98. }
  99. ])
  100. ],
  101. optimization: {
  102. splitChunks: {
  103. chunks: 'all',
  104. cacheGroups: {
  105. libs: {
  106. name: 'chunk-libs',
  107. test: /[\\/]node_modules[\\/]/,
  108. priority: 10,
  109. chunks: 'initial' // 只打包初始时依赖的第三方
  110. },
  111. elementUI: {
  112. name: 'chunk-elementUI', // 单独将 elementUI 拆包
  113. priority: 20, // 权重要大于 libs 和 app 不然会被打包进 libs 或者 app
  114. test: /[\\/]node_modules[\\/]element-ui[\\/]/
  115. },
  116. commons: {
  117. name: 'chunk-commons',
  118. test: resolve('src/components'), // 可自定义拓展你的规则
  119. minChunks: 3, // 最小公用次数
  120. priority: 5,
  121. reuseExistingChunk: true
  122. }
  123. }
  124. },
  125. runtimeChunk: 'single',
  126. minimizer: [
  127. new UglifyJsPlugin({
  128. uglifyOptions: {
  129. mangle: {
  130. safari10: true
  131. }
  132. },
  133. sourceMap: config.build.productionSourceMap,
  134. cache: true,
  135. parallel: true
  136. }),
  137. // Compress extracted CSS. We are using this plugin so that possible
  138. // duplicated CSS from different components can be deduped.
  139. new OptimizeCSSAssetsPlugin()
  140. ]
  141. }
  142. })
  143. if (config.build.productionGzip) {
  144. const CompressionWebpackPlugin = require('compression-webpack-plugin')
  145. webpackConfig.plugins.push(
  146. new CompressionWebpackPlugin({
  147. asset: '[path].gz[query]',
  148. algorithm: 'gzip',
  149. test: new RegExp(
  150. '\\.(' + config.build.productionGzipExtensions.join('|') + ')$'
  151. ),
  152. threshold: 10240,
  153. minRatio: 0.8
  154. })
  155. )
  156. }
  157. if (config.build.generateAnalyzerReport || config.build.bundleAnalyzerReport) {
  158. const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
  159. .BundleAnalyzerPlugin
  160. if (config.build.bundleAnalyzerReport) {
  161. webpackConfig.plugins.push(
  162. new BundleAnalyzerPlugin({
  163. analyzerPort: 8080,
  164. generateStatsFile: false
  165. })
  166. )
  167. }
  168. if (config.build.generateAnalyzerReport) {
  169. webpackConfig.plugins.push(
  170. new BundleAnalyzerPlugin({
  171. analyzerMode: 'static',
  172. reportFilename: 'bundle-report.html',
  173. openAnalyzer: false
  174. })
  175. )
  176. }
  177. }
  178. module.exports = webpackConfig