@ -7,17 +7,23 @@ const merge = require('webpack-merge')
const baseWebpackConfig = require ( './webpack.base.conf' )
const CopyWebpackPlugin = require ( 'copy-webpack-plugin' )
const HtmlWebpackPlugin = require ( 'html-webpack-plugin' )
const ExtractTextPlugin = require ( 'extract-text-webpack-plugin' )
const OptimizeCSSPlugin = require ( 'optimize-css-assets-webpack-plugin' )
const ScriptExtHtmlWebpackPlugin = require ( 'script-ext-html-webpack-plugin' )
const MiniCssExtractPlugin = require ( 'mini-css-extract-plugin' )
const OptimizeCSSAssetsPlugin = require ( 'optimize-css-assets-webpack-plugin' )
const UglifyJsPlugin = require ( 'uglifyjs-webpack-plugin' )
function resolve ( dir ) {
function resolve ( dir ) {
return path . join ( _ _dirname , '..' , dir )
}
const env = require ( '../config/prod.env' )
// For NamedChunksPlugin
const seen = new Set ( )
const nameLength = 4
const webpackConfig = merge ( baseWebpackConfig , {
mode : 'production' ,
module : {
rules : utils . styleLoaders ( {
sourceMap : config . build . productionSourceMap ,
@ -28,37 +34,18 @@ const webpackConfig = merge(baseWebpackConfig, {
devtool : config . build . productionSourceMap ? config . build . devtool : false ,
output : {
path : config . build . assetsRoot ,
filename : utils . assetsPath ( 'js/[name].[chunkhash ].js') ,
chunkFilename : utils . assetsPath ( 'js/[ id].[chunkhash ].js')
filename : utils . assetsPath ( 'js/[name].[chunkhash :8 ].js') ,
chunkFilename : utils . assetsPath ( 'js/[ name].[chunkhash:8 ].js')
} ,
plugins : [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack . DefinePlugin ( {
'process.env' : env
} ) ,
new UglifyJsPlugin ( {
uglifyOptions : {
compress : {
warnings : false
}
} ,
sourceMap : config . build . productionSourceMap ,
parallel : true
} ) ,
// extract css into its own file
new ExtractTextPlugin ( {
filename : utils . assetsPath ( 'css/[name].[contenthash].css' ) ,
// Setting the following option to `false` will not extract CSS from codesplit chunks.
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
allChunks : false ,
} ) ,
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin ( {
cssProcessorOptions : config . build . productionSourceMap
? { safe : true , map : { inline : false } }
: { safe : true }
new MiniCssExtractPlugin ( {
filename : utils . assetsPath ( 'css/[name].[contenthash:8].css' ) ,
chunkFilename : utils . assetsPath ( 'css/[name].[contenthash:8].css' )
} ) ,
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
@ -75,44 +62,34 @@ const webpackConfig = merge(baseWebpackConfig, {
removeAttributeQuotes : true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
} ,
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode : 'dependency'
} ) ,
// keep module.id stable when vender modules does not change
new webpack . HashedModuleIdsPlugin ( ) ,
// enable scope hoisting
new webpack . optimize . ModuleConcatenationPlugin ( ) ,
// split vendor js into its own file
new webpack . optimize . CommonsChunkPlugin ( {
name : 'vendor' ,
minChunks ( module ) {
// any required modules inside node_modules are extracted to vendor
return (
module . resource &&
/\.js$/ . test ( module . resource ) &&
module . resource . indexOf (
path . join ( _ _dirname , '../node_modules' )
) === 0
)
}
// default sort mode uses toposort which cannot handle cyclic deps
// in certain cases, and in webpack 4, chunk order in HTML doesn't
// matter anyway
} ) ,
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack . optimize . CommonsChunkPlugin ( {
name : 'manifest' ,
minChunks : Infinity
new ScriptExtHtmlWebpackPlugin ( {
//`runtime` must same as runtimeChunk name. default is `runtime`
inline : /runtime\..*\.js$/
} ) ,
// This instance extracts shared chunks from code splitted chunks and bundles them
// in a separate chunk, similar to the vendor chunk
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
new webpack . optimize . CommonsChunkPlugin ( {
name : 'app' ,
async : 'vendor-async' ,
children : true ,
minChunks : 3
// keep chunk.id stable when chunk has no name
new webpack . NamedChunksPlugin ( chunk => {
if ( chunk . name ) {
return chunk . name
}
const modules = Array . from ( chunk . modulesIterable )
if ( modules . length > 1 ) {
const hash = require ( 'hash-sum' )
const joinedHash = hash ( modules . map ( m => m . id ) . join ( '_' ) )
let len = nameLength
while ( seen . has ( joinedHash . substr ( 0 , len ) ) ) len ++
seen . add ( joinedHash . substr ( 0 , len ) )
return ` chunk- ${ joinedHash . substr ( 0 , len ) } `
} else {
return modules [ 0 ] . id
}
} ) ,
// keep module.id stable when vender modules does not change
new webpack . HashedModuleIdsPlugin ( ) ,
// copy custom static assets
new CopyWebpackPlugin ( [
{
@ -121,7 +98,41 @@ const webpackConfig = merge(baseWebpackConfig, {
ignore : [ '.*' ]
}
] )
] ,
optimization : {
splitChunks : {
chunks : 'all' ,
cacheGroups : {
libs : {
name : 'chunk-libs' ,
test : /[\\/]node_modules[\\/]/ ,
priority : 10 ,
chunks : 'initial' // 只打包初始时依赖的第三方
} ,
elementUI : {
name : 'chunk-elementUI' , // 单独将 elementUI 拆包
priority : 20 , // 权重要大于 libs 和 app 不然会被打包进 libs 或者 app
test : /[\\/]node_modules[\\/]element-ui[\\/]/
}
}
} ,
runtimeChunk : 'single' ,
minimizer : [
new UglifyJsPlugin ( {
uglifyOptions : {
mangle : {
safari10 : true
}
} ,
sourceMap : config . build . productionSourceMap ,
cache : true ,
parallel : true
} ) ,
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSAssetsPlugin ( )
]
}
} )
if ( config . build . productionGzip ) {
@ -132,9 +143,7 @@ if (config.build.productionGzip) {
asset : '[path].gz[query]' ,
algorithm : 'gzip' ,
test : new RegExp (
'\\.(' +
config . build . productionGzipExtensions . join ( '|' ) +
')$'
'\\.(' + config . build . productionGzipExtensions . join ( '|' ) + ')$'
) ,
threshold : 10240 ,
minRatio : 0.8
@ -142,9 +151,28 @@ if (config.build.productionGzip) {
)
}
if ( config . build . bundleAnalyzerReport ) {
const BundleAnalyzerPlugin = require ( 'webpack-bundle-analyzer' ) . BundleAnalyzerPlugin
webpackConfig . plugins . push ( new BundleAnalyzerPlugin ( ) )
if ( config . build . generateAnalyzerReport || config . build . bundleAnalyzerReport ) {
const BundleAnalyzerPlugin = require ( 'webpack-bundle-analyzer' )
. BundleAnalyzerPlugin
if ( config . build . bundleAnalyzerReport ) {
webpackConfig . plugins . push (
new BundleAnalyzerPlugin ( {
analyzerPort : 8080 ,
generateStatsFile : false
} )
)
}
if ( config . build . generateAnalyzerReport ) {
webpackConfig . plugins . push (
new BundleAnalyzerPlugin ( {
analyzerMode : 'static' ,
reportFilename : 'bundle-report.html' ,
openAnalyzer : false
} )
)
}
}
module . exports = webpackConfig