1 // 此文件是生产环境下webpack相关配置 2 'use strict' 3 const path = require('path') 4 const utils = require('./utils') 5 const webpack = require('webpack') 6 const config = require('../config') // 引入全局配置 7 const merge = require('webpack-merge') // webpack-merge插件提供合并功能,将多个对象合并创建一个新对象。 8 const baseWebpackConfig = require('./webpack.base.conf') 9 const CopyWebpackPlugin = require('copy-webpack-plugin') // 用来复制 10 const HtmlWebpackPlugin = require('html-webpack-plugin') // 自动生成html文件 11 // const ExtractTextPlugin = require('extract-text-webpack-plugin') // 用来抽离css 防止css打包压缩到js中 12 const MiniCssExtractPlugin = require('mini-css-extract-plugin') //将css单独打包成一个文件的插件,它为每个包含css的js文件都创建一个css文件 13 const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') // 用来压缩单独的css文件 14 const UglifyJsPlugin = require('uglifyjs-webpack-plugin') //用来压缩 15 16 //导入prod.env.js 用来区分是生产环境 17 const env = process.env.NODE_ENV === 'testing' ? 18 require('../config/test.env') : 19 require('../config/prod.env') 20 21 // 合并 22 const webpackConfig = merge(baseWebpackConfig, { 23 mode: 'production', 24 module: { 25 // 配置独立的css文件的解析规则 26 rules: utils.styleLoaders({ 27 sourceMap: config.build.productionSourceMap, 28 // 生成独立的文件 29 extract: true, 30 usePostCSS: true 31 }) 32 }, 33 // 开发工具 用来调试 34 devtool: config.build.productionSourceMap ? config.build.devtool : false, 35 // 输出 36 output: { 37 // 打包后的文件放在dist目录下面 38 path: config.build.assetsRoot, 39 // 编译生成的js文件存放在根目录下的js目录下,如果js文件夹不存在就自动创建 40 filename: utils.assetsPath('js/[name].[chunkhash].js'), 41 // 用来打包require.ensure方法中引入的模块,如果该方法中没有引入任何模块,就不会生成chunk文件 42 chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 43 }, 44 // 优化 (https://webpack.docschina.org/configuration/optimization/) 45 optimization: { 46 moduleIds: 'hashed', // 告知 webpack 当选择模块 id 时需要使用哪种算法 ( 'hashed' 相应地会在 webpack 5 中废弃,被 'deterministic' 代替 ) 47 // 拆分模块 (https://www.cnblogs.com/kwzm/p/10314438.html) 48 splitChunks: { 49 chunks: 'async', // 选择用于确定共享模块的块(默认为“async”、“initial”和“all”需要将这些块添加到HTML中) 50 minSize: 30000, // 创建块的大小 51 // minRemainingSize: 0, 52 maxSize: 0, 53 minChunks: 1, 54 maxAsyncRequests: 6, 55 maxInitialRequests: 4, 56 automaticNameDelimiter: '~', 57 cacheGroups: { 58 defaultVendors: { 59 test: /[\/]node_modules[\/]/, 60 priority: -10 61 }, 62 default: { 63 minChunks: 2, 64 priority: -20, 65 reuseExistingChunk: true 66 }, 67 elementUI: { 68 name: "chunk-elementUI", // 单独将 elementUI 拆包 69 priority: 15, // 权重需大于其它缓存组 70 test: /[/]node_modules[/]element-ui[/]/ 71 } 72 } 73 } 74 }, 75 //配置插件项 76 plugins: [ 77 // http://vuejs.github.io/vue-loader/en/workflow/production.html 78 // 自定义一个plugin 生成当前环境下的一个变量 79 new webpack.DefinePlugin({ 80 'process.env': env 81 }), 82 //压缩 83 new UglifyJsPlugin({ 84 uglifyOptions: { 85 // 禁止压缩警告信息 86 warnings: false 87 }, 88 sourceMap: config.build.productionSourceMap, //是否开启sourceMap 用来调试 89 parallel: true //在系统的CPU有多于一个内核时自动启用 仅作用于生产构建 90 }), 91 // 将css解压缩到它自己的文件中 92 new MiniCssExtractPlugin({ 93 //文件名 94 filename: utils.assetsPath('css/app.[name].css'), 95 chunkFilename: utils.assetsPath('css/app.[contenthash:12].css'), // use contenthash * 96 }), 97 //压缩提取CSS。我们使用这个插件,所以可以从不同的组件复制CSS。 98 new OptimizeCSSPlugin({ 99 cssProcessorOptions: config.build.productionSourceMap ? { 100 safe: true, 101 map: { 102 inline: false 103 } 104 } : { 105 safe: true 106 } 107 }), 108 // generate dist index.html with correct asset hash for caching. 109 // you can customize output by editing /index.html 110 // see https://github.com/ampedandwired/html-webpack-plugin 111 new HtmlWebpackPlugin({ 112 filename: process.env.NODE_ENV === 'testing' ? 113 'index.html' : config.build.index, 114 template: 'index.html', 115 favicon: path.resolve(__dirname, '../static/images/favicon.ico'), 116 inject: true, 117 minify: { 118 removeComments: true, 119 collapseWhitespace: true, 120 removeAttributeQuotes: true 121 // more options: 122 // https://github.com/kangax/html-minifier#options-quick-reference 123 }, 124 // necessary to consistently work with multiple chunks via CommonsChunkPlugin 125 chunksSortMode: 'manual', 126 dll: (function () { 127 let max = 2 128 let res = [] 129 for (let i = 0; i < max; i++) { 130 const dllName = require(path.resolve(__dirname, `../dllManifest/xuAdmin${i}-manifest.json`)).name.split('_') 131 res.push(`./static/dll/${dllName[0]}.${dllName[1]}.dll.js`) 132 } 133 return res 134 })() 135 }), 136 // keep module.id stable when vendor modules does not change 137 new webpack.HashedModuleIdsPlugin(), 138 // enable scope hoisting 139 new webpack.optimize.ModuleConcatenationPlugin(), 140 // split vendor js into its own file 141 142 // extract webpack runtime and module manifest to its own file in order to 143 // prevent vendor hash from being updated whenever app bundle is updated 144 145 // This instance extracts shared chunks from code splitted chunks and bundles them 146 // in a separate chunk, similar to the vendor chunk 147 // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk 148 149 150 // 复制自定义静态资产 151 new CopyWebpackPlugin([{ 152 from: path.resolve(__dirname, '../static'), 153 to: config.build.assetsSubDirectory, 154 ignore: ['.*'] 155 }]), 156 ] 157 }) 158 159 160 //压缩 161 if (config.build.productionGzip) { 162 const CompressionWebpackPlugin = require('compression-webpack-plugin') 163 164 webpackConfig.plugins.push( 165 new CompressionWebpackPlugin({ 166 asset: '[path].gz[query]', // 目标资源名称 [path]会被替换成原始资源的路径 [query]会被替换成查询字符串 167 algorithm: 'gzip', // 按照zlib的算法 168 // 所有匹配该正则的资源都会被处理 默认值是全部资源 169 test: new RegExp( 170 '\.(' + 171 config.build.productionGzipExtensions.join('|') + 172 ')$' 173 ), 174 threshold: 10240, // 只有大小大于该值得资源会被处理,单位是bytes 175 minRatio: 0.8 // 压缩率小于这个值得资源才会被处理 默认值是 0.8 176 }) 177 ) 178 } 179 180 //打包文件分析工具 181 if (config.build.bundleAnalyzerReport) { 182 const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 183 webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 184 } 185 186 //导出 187 module.exports = webpackConfig 188 // 此文件是生产环境下webpack相关配置 189 'use strict' 190 const path = require('path') 191 const utils = require('./utils') 192 const webpack = require('webpack') 193 const config = require('../config') // 引入全局配置 194 const merge = require('webpack-merge') // webpack-merge插件提供合并功能,将多个对象合并创建一个新对象。 195 const baseWebpackConfig = require('./webpack.base.conf') 196 const CopyWebpackPlugin = require('copy-webpack-plugin') // 用来复制 197 const HtmlWebpackPlugin = require('html-webpack-plugin') // 自动生成html文件 198 // const ExtractTextPlugin = require('extract-text-webpack-plugin') // 用来抽离css 防止css打包压缩到js中 199 const MiniCssExtractPlugin = require('mini-css-extract-plugin') //将css单独打包成一个文件的插件,它为每个包含css的js文件都创建一个css文件 200 const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') // 用来压缩单独的css文件 201 const UglifyJsPlugin = require('uglifyjs-webpack-plugin') //用来压缩 202 203 //导入prod.env.js 用来区分是生产环境 204 const env = process.env.NODE_ENV === 'testing' ? 205 require('../config/test.env') : 206 require('../config/prod.env') 207 208 // 合并 209 const webpackConfig = merge(baseWebpackConfig, { 210 mode: 'production', 211 module: { 212 // 配置独立的css文件的解析规则 213 rules: utils.styleLoaders({ 214 sourceMap: config.build.productionSourceMap, 215 // 生成独立的文件 216 extract: true, 217 usePostCSS: true 218 }) 219 }, 220 // 开发工具 用来调试 221 devtool: config.build.productionSourceMap ? config.build.devtool : false, 222 // 输出 223 output: { 224 // 打包后的文件放在dist目录下面 225 path: config.build.assetsRoot, 226 // 编译生成的js文件存放在根目录下的js目录下,如果js文件夹不存在就自动创建 227 filename: utils.assetsPath('js/[name].[chunkhash].js'), 228 // 用来打包require.ensure方法中引入的模块,如果该方法中没有引入任何模块,就不会生成chunk文件 229 chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 230 }, 231 // 优化 (https://webpack.docschina.org/configuration/optimization/) 232 optimization: { 233 moduleIds: 'hashed', // 告知 webpack 当选择模块 id 时需要使用哪种算法 ( 'hashed' 相应地会在 webpack 5 中废弃,被 'deterministic' 代替 ) 234 // 拆分模块 (https://www.cnblogs.com/kwzm/p/10314438.html) 235 splitChunks: { 236 chunks: 'async', // 选择用于确定共享模块的块(默认为“async”、“initial”和“all”需要将这些块添加到HTML中) 237 minSize: 30000, // 创建块的大小 238 // minRemainingSize: 0, 239 maxSize: 0, 240 minChunks: 1, 241 maxAsyncRequests: 6, 242 maxInitialRequests: 4, 243 automaticNameDelimiter: '~', 244 cacheGroups: { 245 defaultVendors: { 246 test: /[\/]node_modules[\/]/, 247 priority: -10 248 }, 249 default: { 250 minChunks: 2, 251 priority: -20, 252 reuseExistingChunk: true 253 }, 254 elementUI: { 255 name: "chunk-elementUI", // 单独将 elementUI 拆包 256 priority: 15, // 权重需大于其它缓存组 257 test: /[/]node_modules[/]element-ui[/]/ 258 } 259 } 260 } 261 }, 262 //配置插件项 263 plugins: [ 264 // http://vuejs.github.io/vue-loader/en/workflow/production.html 265 // 自定义一个plugin 生成当前环境下的一个变量 266 new webpack.DefinePlugin({ 267 'process.env': env 268 }), 269 //压缩 270 new UglifyJsPlugin({ 271 uglifyOptions: { 272 // 禁止压缩警告信息 273 warnings: false 274 }, 275 sourceMap: config.build.productionSourceMap, //是否开启sourceMap 用来调试 276 parallel: true //在系统的CPU有多于一个内核时自动启用 仅作用于生产构建 277 }), 278 // 将css解压缩到它自己的文件中 279 new MiniCssExtractPlugin({ 280 //文件名 281 filename: utils.assetsPath('css/app.[name].css'), 282 chunkFilename: utils.assetsPath('css/app.[contenthash:12].css'), // use contenthash * 283 }), 284 //压缩提取CSS。我们使用这个插件,所以可以从不同的组件复制CSS。 285 new OptimizeCSSPlugin({ 286 cssProcessorOptions: config.build.productionSourceMap ? { 287 safe: true, 288 map: { 289 inline: false 290 } 291 } : { 292 safe: true 293 } 294 }), 295 // generate dist index.html with correct asset hash for caching. 296 // you can customize output by editing /index.html 297 // see https://github.com/ampedandwired/html-webpack-plugin 298 new HtmlWebpackPlugin({ 299 filename: process.env.NODE_ENV === 'testing' ? 300 'index.html' : config.build.index, 301 template: 'index.html', 302 favicon: path.resolve(__dirname, '../static/images/favicon.ico'), 303 inject: true, 304 minify: { 305 removeComments: true, 306 collapseWhitespace: true, 307 removeAttributeQuotes: true 308 // more options: 309 // https://github.com/kangax/html-minifier#options-quick-reference 310 }, 311 // necessary to consistently work with multiple chunks via CommonsChunkPlugin 312 chunksSortMode: 'manual', 313 dll: (function () { 314 let max = 2 315 let res = [] 316 for (let i = 0; i < max; i++) { 317 const dllName = require(path.resolve(__dirname, `../dllManifest/xuAdmin${i}-manifest.json`)).name.split('_') 318 res.push(`./static/dll/${dllName[0]}.${dllName[1]}.dll.js`) 319 } 320 return res 321 })() 322 }), 323 // keep module.id stable when vendor modules does not change 324 new webpack.HashedModuleIdsPlugin(), 325 // enable scope hoisting 326 new webpack.optimize.ModuleConcatenationPlugin(), 327 // split vendor js into its own file 328 329 // extract webpack runtime and module manifest to its own file in order to 330 // prevent vendor hash from being updated whenever app bundle is updated 331 332 // This instance extracts shared chunks from code splitted chunks and bundles them 333 // in a separate chunk, similar to the vendor chunk 334 // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk 335 336 337 // 复制自定义静态资产 338 new CopyWebpackPlugin([{ 339 from: path.resolve(__dirname, '../static'), 340 to: config.build.assetsSubDirectory, 341 ignore: ['.*'] 342 }]), 343 ] 344 }) 345 346 347 //压缩 348 if (config.build.productionGzip) { 349 const CompressionWebpackPlugin = require('compression-webpack-plugin') 350 351 webpackConfig.plugins.push( 352 new CompressionWebpackPlugin({ 353 asset: '[path].gz[query]', // 目标资源名称 [path]会被替换成原始资源的路径 [query]会被替换成查询字符串 354 algorithm: 'gzip', // 按照zlib的算法 355 // 所有匹配该正则的资源都会被处理 默认值是全部资源 356 test: new RegExp( 357 '\.(' + 358 config.build.productionGzipExtensions.join('|') + 359 ')$' 360 ), 361 threshold: 10240, // 只有大小大于该值得资源会被处理,单位是bytes 362 minRatio: 0.8 // 压缩率小于这个值得资源才会被处理 默认值是 0.8 363 }) 364 ) 365 } 366 367 //打包文件分析工具 368 if (config.build.bundleAnalyzerReport) { 369 const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 370 webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 371 } 372 373 //导出 374 module.exports = webpackConfig