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 ) {
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' )
2017-01-05 03:34:12 +08:00
2017-01-10 19:15:41 +08:00
You would change it to :
new webpack . optimize . CommonsChunkPlugin ( { name : 'vendor' , filename : 'vendor.bundle.js' } )
2017-01-05 03:34:12 +08:00
2017-01-10 19:15:41 +08:00
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-10 19:47:29 +08:00
const optimized = new WeakSet ( ) ;
2017-01-04 21:50:00 +08:00
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
2017-01-10 19:47:29 +08:00
if ( optimized . has ( compilation ) ) return ;
optimized . add ( compilation )
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-10 19:47:29 +08:00
commonChunks = [ ] . concat ( chunkNames ) . map ( chunkName =>
chunks . find ( chunk => chunk . name === chunkName ) || compilation . addChunk ( chunkName ) ) ;
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 ) {
2017-01-10 19:47:29 +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-10 19:47:29 +08:00
asyncOption || chunk . parents . length === 1 ) ;
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-10 19:47:29 +08:00
usedChunks = chunks . filter ( chunk => commonChunks . indexOf ( chunk ) < idx && chunk . hasRuntime ( ) )
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-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 ) {
2017-01-10 19:47:29 +08:00
const size = reallyUsedModules . reduce ( ( a , b ) => 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
}
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 ;