2013-12-03 16:27:15 +08:00
/ *
MIT License http : //www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @ sokra
* /
2017-01-04 21:50:00 +08:00
"use strict" ;
let nextIdent = 0 ;
2015-11-21 04:29:32 +08:00
2017-01-04 21:50:00 +08:00
class CommonsChunkPlugin {
constructor ( options ) {
if ( arguments . length > 1 ) {
throw new Error ( "Deprecation notice: CommonsChunkPlugin now only takes a single argument. Either an options " +
"object *or* the name of the chunk.\n" +
"Example: if your old code looked like this:\n" +
" new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js')\n\n" +
"You would change it to:\n" +
" new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js' })\n\n" +
"The available options are:\n" +
" name: string\n" +
" names: string[]\n" +
" filename: string\n" +
" minChunks: number\n" +
" chunks: string[]\n" +
" children: boolean\n" +
" async: boolean\n" +
" minSize: number\n" ) ;
}
if ( Array . isArray ( options ) || typeof options === "string" ) {
options = {
name : options
} ;
}
this . chunkNames = options . name || options . names ;
this . filenameTemplate = options . filename ;
this . minChunks = options . minChunks ;
this . selectedChunks = options . chunks ;
if ( options . children ) this . selectedChunks = false ;
this . async = options . async ;
this . minSize = options . minSize ;
this . ident = _ _filename + ( nextIdent ++ ) ;
2016-01-22 12:01:00 +08:00
}
2017-01-04 21:50:00 +08:00
apply ( compiler ) {
const chunkNames = this . chunkNames ;
const filenameTemplate = this . filenameTemplate ;
const minChunks = this . minChunks ;
const selectedChunks = this . selectedChunks ;
const asyncOption = this . async ;
const minSize = this . minSize ;
const ident = this . ident ;
compiler . plugin ( "this-compilation" , ( compilation ) => {
2017-01-04 22:56:46 +08:00
compilation . plugin ( [ "optimize-chunks" , "optimize-extracted-chunks" ] , ( chunks ) => {
2017-01-04 21:50:00 +08:00
// only optimize once
if ( compilation [ ident ] ) return ;
compilation [ ident ] = true ;
2015-11-21 04:29:32 +08:00
2017-01-04 21:50:00 +08:00
let commonChunks ;
if ( ! chunkNames && ( selectedChunks === false || asyncOption ) ) {
commonChunks = chunks ;
} else if ( Array . isArray ( chunkNames ) || typeof chunkNames === "string" ) {
commonChunks = [ ] . concat ( chunkNames ) . map ( ( chunkName ) => {
2017-01-04 22:56:46 +08:00
let chunk = chunks . filter ( ( chunk ) => {
2017-01-04 21:50:00 +08:00
return chunk . name === chunkName ;
} ) [ 0 ] ;
if ( ! chunk ) {
2017-01-04 22:56:46 +08:00
chunk = compilation . addChunk ( chunkName ) ;
2017-01-04 21:50:00 +08:00
}
return chunk ;
} , this ) ;
2014-12-22 19:33:11 +08:00
} else {
2017-01-04 21:50:00 +08:00
throw new Error ( "Invalid chunkNames argument" ) ;
2014-12-22 19:33:11 +08:00
}
2017-01-04 21:50:00 +08:00
commonChunks . forEach ( function processCommonChunk ( commonChunk , idx ) {
let usedChunks ;
if ( Array . isArray ( selectedChunks ) ) {
usedChunks = chunks . filter ( ( chunk ) => {
if ( chunk === commonChunk ) return false ;
return selectedChunks . indexOf ( chunk . name ) >= 0 ;
2016-04-07 01:51:09 +08:00
} ) ;
2017-01-04 21:50:00 +08:00
} else if ( selectedChunks === false || asyncOption ) {
usedChunks = ( commonChunk . chunks || [ ] ) . filter ( ( chunk ) => {
// we can only move modules from this chunk if the "commonChunk" is the only parent
return asyncOption || chunk . parents . length === 1 ;
} ) ;
} else {
if ( commonChunk . parents . length > 0 ) {
compilation . errors . push ( new Error ( "CommonsChunkPlugin: While running in normal mode it's not allowed to use a non-entry chunk (" + commonChunk . name + ")" ) ) ;
2016-11-10 15:52:00 +08:00
return ;
2015-01-12 06:15:11 +08:00
}
2017-01-04 21:50:00 +08:00
usedChunks = chunks . filter ( ( chunk ) => {
const found = commonChunks . indexOf ( chunk ) ;
if ( found >= idx ) return false ;
return chunk . hasRuntime ( ) ;
} ) ;
}
2017-01-04 22:56:46 +08:00
let asyncChunk ;
2017-01-04 21:50:00 +08:00
if ( asyncOption ) {
2017-01-04 22:56:46 +08:00
asyncChunk = compilation . addChunk ( typeof asyncOption === "string" ? asyncOption : undefined ) ;
2017-01-04 21:50:00 +08:00
asyncChunk . chunkReason = "async commons chunk" ;
asyncChunk . extraAsync = true ;
asyncChunk . addParent ( commonChunk ) ;
commonChunk . addChunk ( asyncChunk ) ;
commonChunk = asyncChunk ;
}
const reallyUsedModules = [ ] ;
if ( minChunks !== Infinity ) {
const commonModulesCount = [ ] ;
const commonModules = [ ] ;
2017-01-04 22:56:46 +08:00
usedChunks . forEach ( ( chunk ) => {
chunk . modules . forEach ( ( module ) => {
2017-01-04 21:50:00 +08:00
const idx = commonModules . indexOf ( module ) ;
if ( idx < 0 ) {
commonModules . push ( module ) ;
commonModulesCount . push ( 1 ) ;
} else {
commonModulesCount [ idx ] ++ ;
}
} ) ;
} ) ;
const _minChunks = ( minChunks || Math . max ( 2 , usedChunks . length ) )
commonModulesCount . forEach ( ( count , idx ) => {
const module = commonModules [ idx ] ;
if ( typeof minChunks === "function" ) {
if ( ! minChunks ( module , count ) )
return ;
} else if ( count < _minChunks ) {
return ;
}
if ( module . chunkCondition && ! module . chunkCondition ( commonChunk ) )
return ;
reallyUsedModules . push ( module ) ;
} ) ;
}
if ( minSize ) {
const size = reallyUsedModules . reduce ( ( a , b ) => {
return a + b . size ( ) ;
} , 0 ) ;
if ( size < minSize )
2015-01-12 06:15:11 +08:00
return ;
2017-01-04 21:50:00 +08:00
}
const reallyUsedChunks = [ ] ;
reallyUsedModules . forEach ( ( module ) => {
usedChunks . forEach ( ( chunk ) => {
if ( module . removeChunk ( chunk ) ) {
if ( reallyUsedChunks . indexOf ( chunk ) < 0 )
reallyUsedChunks . push ( chunk ) ;
}
2015-01-12 06:15:11 +08:00
} ) ;
2017-01-04 21:50:00 +08:00
commonChunk . addModule ( module ) ;
module . addChunk ( commonChunk ) ;
2015-01-12 06:15:11 +08:00
} ) ;
2017-01-04 21:50:00 +08:00
if ( asyncOption ) {
reallyUsedChunks . forEach ( ( chunk ) => {
if ( chunk . isInitial ( ) )
return ;
chunk . blocks . forEach ( ( block ) => {
block . chunks . unshift ( commonChunk ) ;
commonChunk . addBlock ( block ) ;
} ) ;
2015-01-12 06:15:11 +08:00
} ) ;
2017-01-04 21:50:00 +08:00
asyncChunk . origins = reallyUsedChunks . map ( ( chunk ) => {
2017-01-04 22:56:46 +08:00
return chunk . origins . map ( ( origin ) => {
2017-01-04 21:50:00 +08:00
const newOrigin = Object . create ( origin ) ;
newOrigin . reasons = ( origin . reasons || [ ] ) . slice ( ) ;
newOrigin . reasons . push ( "async commons" ) ;
return newOrigin ;
} ) ;
} ) . reduce ( ( arr , a ) => {
arr . push . apply ( arr , a ) ;
return arr ;
} , [ ] ) ;
} else {
usedChunks . forEach ( ( chunk ) => {
chunk . parents = [ commonChunk ] ;
chunk . entrypoints . forEach ( ( ep ) => {
ep . insertChunk ( commonChunk , chunk ) ;
} ) ;
commonChunk . addChunk ( chunk ) ;
2016-07-13 17:03:14 +08:00
} ) ;
2017-01-04 21:50:00 +08:00
}
if ( filenameTemplate )
commonChunk . filenameTemplate = filenameTemplate ;
} , this ) ;
return true ;
} ) ;
2013-12-03 16:27:15 +08:00
} ) ;
2017-01-04 21:50:00 +08:00
}
}
module . exports = CommonsChunkPlugin ;