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 ;
class CommonsChunkPlugin {
constructor ( options ) {
if ( arguments . length > 1 ) {
2017-01-05 03:34:12 +08:00
throw new Error ( ` Deprecation notice: CommonsChunkPlugin now only takes a single argument. Either an options
2017-01-10 19:15:41 +08:00
object * or * the name of the chunk .
Example : if your old code looked like this :
new webpack . optimize . CommonsChunkPlugin ( 'vendor' , 'vendor.bundle.js' )
You would change it to :
new webpack . optimize . CommonsChunkPlugin ( { name : 'vendor' , filename : 'vendor.bundle.js' } )
The available options are :
name : string
names : string [ ]
filename : string
minChunks : number
chunks : string [ ]
children : boolean
async : boolean
minSize : number ` );
2017-01-04 21:50:00 +08:00
}
2017-01-10 19:15:41 +08:00
2017-01-04 21:50:00 +08:00
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 ;
2017-01-24 18:47:12 +08:00
const ident = this . ident ;
2017-01-04 21:50:00 +08:00
compiler . plugin ( "this-compilation" , ( compilation ) => {
2017-01-24 19:09:46 +08:00
compilation . plugin ( [ "optimize-chunks" , "optimize-extracted-chunks" ] , ( chunks ) => {
2017-01-04 21:50:00 +08:00
// only optimize once
2017-01-24 18:47:12 +08:00
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" ) {
2017-01-24 18:47:12 +08:00
commonChunks = [ ] . concat ( chunkNames ) . map ( ( chunkName ) => {
2017-01-24 19:09:46 +08:00
let chunk = chunks . filter ( ( chunk ) => chunk . name === chunkName ) [ 0 ] ;
2017-01-24 18:47:12 +08:00
if ( ! chunk ) {
2017-01-24 19:09:46 +08:00
chunk = compilation . addChunk ( chunkName ) ;
2017-01-24 18:47:12 +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 ) ) {
2017-01-24 18:47:12 +08:00
usedChunks = chunks . filter ( chunk => chunk !== commonChunk && selectedChunks . indexOf ( chunk . name ) >= 0 ) ;
2017-01-04 21:50:00 +08:00
} else if ( selectedChunks === false || asyncOption ) {
2017-01-24 18:47:12 +08:00
usedChunks = ( commonChunk . chunks || [ ] ) . filter ( ( chunk ) => {
2017-01-04 21:50:00 +08:00
// we can only move modules from this chunk if the "commonChunk" is the only parent
2017-01-24 18:47:12 +08:00
return asyncOption || chunk . parents . length === 1 ;
2016-04-07 01:51:09 +08:00
} ) ;
2017-01-04 21:50:00 +08:00
} 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-24 18:47:12 +08:00
usedChunks = chunks . filter ( ( chunk ) => {
const found = commonChunks . indexOf ( chunk ) ;
if ( found >= idx ) return false ;
return chunk . hasRuntime ( ) ;
2015-01-12 06:15:11 +08:00
} ) ;
2017-01-04 21:50:00 +08:00
}
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-24 19:09: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 ] ++ ;
}
} ) ;
} ) ;
2017-01-24 18:47:12 +08:00
const _minChunks = ( minChunks || Math . max ( 2 , usedChunks . length ) ) ;
2017-01-04 21:50:00 +08:00
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 ) {
2017-01-24 18:47:12 +08:00
const size = reallyUsedModules . reduce ( ( a , b ) => {
return a + b . size ( ) ;
} , 0 ) ;
2017-01-04 21:50:00 +08:00
if ( size < minSize )
2015-01-12 06:15:11 +08:00
return ;
2017-01-04 21:50:00 +08:00
}
2017-01-24 18:47:12 +08:00
const reallyUsedChunks = new Set ( ) ;
2017-01-04 21:50:00 +08:00
reallyUsedModules . forEach ( ( module ) => {
usedChunks . forEach ( ( chunk ) => {
if ( module . removeChunk ( chunk ) ) {
2017-01-24 18:47:12 +08:00
reallyUsedChunks . add ( chunk ) ;
2017-01-04 21:50:00 +08:00
}
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 ) {
2017-01-24 18:47:12 +08:00
for ( const chunk of reallyUsedChunks ) {
if ( chunk . isInitial ( ) ) continue ;
2017-01-04 21:50:00 +08:00
chunk . blocks . forEach ( ( block ) => {
block . chunks . unshift ( commonChunk ) ;
commonChunk . addBlock ( block ) ;
} ) ;
2017-01-24 18:47:12 +08:00
}
asyncChunk . origins = Array . from ( reallyUsedChunks ) . map ( ( chunk ) => {
2017-01-24 19:09: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 ;
2017-01-24 19:09:46 +08:00
} ) ;
2017-01-04 21:50:00 +08:00
return true ;
} ) ;
2013-12-03 16:27:15 +08:00
} ) ;
2017-01-04 21:50:00 +08:00
}
}
module . exports = CommonsChunkPlugin ;