@@ -73,7 +73,7 @@ class Compilation extends Tapable {
7373 this . chunks = [ ] ;
7474 this . namedChunks = { } ;
7575 this . modules = [ ] ;
76- this . _modules = { } ;
76+ this . _modules = new Map ( ) ;
7777 this . cache = null ;
7878 this . records = null ;
7979 this . nextFreeModuleIndex = undefined ;
@@ -87,6 +87,9 @@ class Compilation extends Tapable {
8787 this . dependencyTemplates = new Map ( ) ;
8888 this . dependencyTemplates . set ( "hash" , "" ) ;
8989 this . childrenCounters = { } ;
90+
91+ this . _buildingModules = new Map ( ) ;
92+ this . _rebuildingModules = new Map ( ) ;
9093 }
9194
9295 getStats ( ) {
@@ -100,29 +103,29 @@ class Compilation extends Tapable {
100103
101104 addModule ( module , cacheGroup ) {
102105 const identifier = module . identifier ( ) ;
103- if ( this . _modules [ identifier ] ) {
106+ if ( this . _modules . get ( identifier ) ) {
104107 return false ;
105108 }
106109 const cacheName = ( cacheGroup || "m" ) + identifier ;
107110 if ( this . cache && this . cache [ cacheName ] ) {
108111 const cacheModule = this . cache [ cacheName ] ;
109112
110113 let rebuild = true ;
111- if ( ! cacheModule . error && cacheModule . cacheable && this . fileTimestamps && this . contextTimestamps ) {
114+ if ( this . fileTimestamps && this . contextTimestamps ) {
112115 rebuild = cacheModule . needRebuild ( this . fileTimestamps , this . contextTimestamps ) ;
113116 }
114117
115118 if ( ! rebuild ) {
116119 cacheModule . disconnect ( ) ;
117- this . _modules [ identifier ] = cacheModule ;
120+ this . _modules . set ( identifier , cacheModule ) ;
118121 this . modules . push ( cacheModule ) ;
119122 cacheModule . errors . forEach ( err => this . errors . push ( err ) , this ) ;
120123 cacheModule . warnings . forEach ( err => this . warnings . push ( err ) , this ) ;
121124 return cacheModule ;
122125 }
126+ module . unbuild ( ) ;
123127 }
124- module . unbuild ( ) ;
125- this . _modules [ identifier ] = module ;
128+ this . _modules . set ( identifier , module ) ;
126129 if ( this . cache ) {
127130 this . cache [ cacheName ] = module ;
128131 }
@@ -132,22 +135,36 @@ class Compilation extends Tapable {
132135
133136 getModule ( module ) {
134137 const identifier = module . identifier ( ) ;
135- return this . _modules [ identifier ] ;
138+ return this . _modules . get ( identifier ) ;
136139 }
137140
138141 findModule ( identifier ) {
139- return this . _modules [ identifier ] ;
142+ return this . _modules . get ( identifier ) ;
143+ }
144+
145+ waitForBuildingFinished ( module , callback ) {
146+ let callbackList = this . _buildingModules . get ( module ) ;
147+ if ( callbackList ) {
148+ callbackList . push ( ( ) => callback ( ) ) ;
149+ } else {
150+ process . nextTick ( callback ) ;
151+ }
140152 }
141153
142154 buildModule ( module , optional , origin , dependencies , thisCallback ) {
143155 this . applyPlugins1 ( "build-module" , module ) ;
144- if ( module . building ) return module . building . push ( thisCallback ) ;
145- const building = module . building = [ thisCallback ] ;
146-
147- function callback ( err ) {
148- module . building = undefined ;
149- building . forEach ( cb => cb ( err ) ) ;
156+ let callbackList = this . _buildingModules . get ( module ) ;
157+ if ( callbackList ) {
158+ callbackList . push ( thisCallback ) ;
159+ return ;
150160 }
161+ this . _buildingModules . set ( module , callbackList = [ thisCallback ] ) ;
162+
163+ const callback = err => {
164+ this . _buildingModules . delete ( module ) ;
165+ callbackList . forEach ( cb => cb ( err ) ) ;
166+ } ;
167+
151168 module . build ( this . options , this , this . resolvers . normal , this . inputFileSystem , ( error ) => {
152169 const errors = module . errors ;
153170 for ( let indexError = 0 ; indexError < errors . length ; indexError ++ ) {
@@ -252,7 +269,7 @@ class Compilation extends Tapable {
252269 let afterFactory ;
253270
254271 function isOptional ( ) {
255- return dependencies . filter ( d => ! d . optional ) . length === 0 ;
272+ return dependencies . every ( d => d . optional ) ;
256273 }
257274
258275 function errorOrWarningAndCallback ( err ) {
@@ -287,16 +304,11 @@ class Compilation extends Tapable {
287304 dependentModule . profile . factory = afterFactory - start ;
288305 }
289306
290- dependentModule . issuer = module ;
291307 const newModule = _this . addModule ( dependentModule , cacheGroup ) ;
292308
293309 if ( ! newModule ) { // from cache
294310 dependentModule = _this . getModule ( dependentModule ) ;
295311
296- if ( dependentModule . optional ) {
297- dependentModule . optional = isOptional ( ) ;
298- }
299-
300312 iterationDependencies ( dependencies ) ;
301313
302314 if ( _this . profile ) {
@@ -310,16 +322,16 @@ class Compilation extends Tapable {
310322 }
311323
312324 semaphore . release ( ) ;
313- return process . nextTick ( callback ) ;
325+ _this . waitForBuildingFinished ( dependentModule , callback ) ;
326+ return ;
314327 }
315328
316329 if ( newModule instanceof Module ) {
317330 if ( _this . profile ) {
318331 newModule . profile = dependentModule . profile ;
319332 }
320333
321- newModule . optional = isOptional ( ) ;
322- newModule . issuer = dependentModule . issuer ;
334+ newModule . issuer = module ;
323335 dependentModule = newModule ;
324336
325337 iterationDependencies ( dependencies ) ;
@@ -337,7 +349,7 @@ class Compilation extends Tapable {
337349 }
338350 }
339351
340- dependentModule . optional = isOptional ( ) ;
352+ dependentModule . issuer = module ;
341353
342354 iterationDependencies ( dependencies ) ;
343355
@@ -429,13 +441,20 @@ class Compilation extends Tapable {
429441
430442 onModule ( module ) ;
431443
444+ dependency . module = module ;
445+ module . addReason ( null , dependency ) ;
446+
432447 if ( this . profile ) {
433448 const afterBuilding = Date . now ( ) ;
434449 module . profile . building = afterBuilding - afterFactory ;
435450 }
436451
437452 this . semaphore . release ( ) ;
438- return callback ( null , module ) ;
453+ this . waitForBuildingFinished ( module , err => {
454+ if ( err ) return callback ( err ) ;
455+ callback ( null , module ) ;
456+ } ) ;
457+ return ;
439458 }
440459
441460 if ( result instanceof Module ) {
@@ -447,12 +466,18 @@ class Compilation extends Tapable {
447466
448467 onModule ( module ) ;
449468
469+ dependency . module = module ;
470+ module . addReason ( null , dependency ) ;
471+
450472 moduleReady . call ( this ) ;
451473 return ;
452474 }
453475
454476 onModule ( module ) ;
455477
478+ dependency . module = module ;
479+ module . addReason ( null , dependency ) ;
480+
456481 this . buildModule ( module , false , null , null , ( err ) => {
457482 if ( err ) {
458483 this . semaphore . release ( ) ;
@@ -489,9 +514,7 @@ class Compilation extends Tapable {
489514 this . preparedChunks . push ( slot ) ;
490515 this . _addModuleChain ( context , entry , ( module ) => {
491516
492- entry . module = module ;
493517 this . entries . push ( module ) ;
494- module . issuer = null ;
495518
496519 } , ( err , module ) => {
497520 if ( err ) {
@@ -512,39 +535,35 @@ class Compilation extends Tapable {
512535 this . _addModuleChain ( context , dependency , module => {
513536
514537 module . prefetched = true ;
515- module . issuer = null ;
516538
517539 } , callback ) ;
518540 }
519541
520542 rebuildModule ( module , thisCallback ) {
521- if ( module . variables . length || module . blocks . length )
522- throw new Error ( "Cannot rebuild a complex module with variables or blocks" ) ;
523- if ( module . rebuilding ) {
524- return module . rebuilding . push ( thisCallback ) ;
543+ let callbackList = this . _rebuildingModules . get ( module ) ;
544+ if ( callbackList ) {
545+ callbackList . push ( thisCallback ) ;
546+ return ;
525547 }
526- const rebuilding = module . rebuilding = [ thisCallback ] ;
548+ this . _rebuildingModules . set ( module , callbackList = [ thisCallback ] ) ;
527549
528- function callback ( err ) {
529- module . rebuilding = undefined ;
530- rebuilding . forEach ( cb => cb ( err ) ) ;
531- }
532- const deps = module . dependencies . slice ( ) ;
550+ const callback = err => {
551+ this . _rebuildingModules . delete ( module ) ;
552+ callbackList . forEach ( cb => cb ( err ) ) ;
553+ } ;
554+
555+ const oldDependencies = module . dependencies . slice ( ) ;
556+ const oldVariables = module . variables . slice ( ) ;
557+ const oldBlocks = module . blocks . slice ( ) ;
533558 this . buildModule ( module , false , module , null , ( err ) => {
534559 if ( err ) return callback ( err ) ;
535560
536561 this . processModuleDependencies ( module , ( err ) => {
537562 if ( err ) return callback ( err ) ;
538- deps . forEach ( d => {
539- if ( d . module && d . module . removeReason ( module , d ) ) {
540- module . forEachChunk ( chunk => {
541- if ( ! d . module . hasReasonForChunk ( chunk ) ) {
542- if ( d . module . removeChunk ( chunk ) ) {
543- this . removeChunkFromDependencies ( d . module , chunk ) ;
544- }
545- }
546- } ) ;
547- }
563+ this . removeReasonsOfDependencyBlock ( module , {
564+ dependencies : oldDependencies ,
565+ variables : oldVariables ,
566+ blocks : oldBlocks
548567 } ) ;
549568 callback ( ) ;
550569 } ) ;
@@ -1077,16 +1096,46 @@ class Compilation extends Tapable {
10771096 }
10781097 }
10791098
1080- removeChunkFromDependencies ( block , chunk ) {
1099+ removeReasonsOfDependencyBlock ( module , block ) {
10811100 const iteratorDependency = d => {
10821101 if ( ! d . module ) {
10831102 return ;
10841103 }
1085- if ( ! d . module . hasReasonForChunk ( chunk ) ) {
1086- if ( d . module . removeChunk ( chunk ) ) {
1087- this . removeChunkFromDependencies ( d . module , chunk ) ;
1088- }
1104+ if ( d . module . removeReason ( module , d ) ) {
1105+ d . module . forEachChunk ( chunk => this . patchChunksAfterReasonRemoval ( d . module , chunk ) ) ;
1106+ }
1107+ } ;
1108+
1109+ if ( block . blocks ) {
1110+ iterationOfArrayCallback ( block . blocks , block => this . removeReasonsOfDependencyBlock ( module , block ) ) ;
1111+ }
1112+
1113+ if ( block . dependencies ) {
1114+ iterationOfArrayCallback ( block . dependencies , iteratorDependency ) ;
1115+ }
1116+
1117+ if ( block . variables ) {
1118+ iterationBlockVariable ( block . variables , iteratorDependency ) ;
1119+ }
1120+ }
1121+
1122+ patchChunksAfterReasonRemoval ( module , chunk ) {
1123+ if ( ! module . hasReasons ( ) ) {
1124+ this . removeReasonsOfDependencyBlock ( module , module ) ;
1125+ }
1126+ if ( ! module . hasReasonForChunk ( chunk ) ) {
1127+ if ( module . removeChunk ( chunk ) ) {
1128+ this . removeChunkFromDependencies ( module , chunk ) ;
1129+ }
1130+ }
1131+ }
1132+
1133+ removeChunkFromDependencies ( block , chunk ) {
1134+ const iteratorDependency = d => {
1135+ if ( ! d . module ) {
1136+ return ;
10891137 }
1138+ this . patchChunksAfterReasonRemoval ( d . module , chunk ) ;
10901139 } ;
10911140
10921141 const blocks = block . blocks ;
0 commit comments