@@ -80,7 +80,7 @@ class Compilation extends Tapable {
8080 this . chunks = [ ] ;
8181 this . namedChunks = { } ;
8282 this . modules = [ ] ;
83- this . _modules = { } ;
83+ this . _modules = new Map ( ) ;
8484 this . cache = null ;
8585 this . records = null ;
8686 this . nextFreeModuleIndex = undefined ;
@@ -94,6 +94,9 @@ class Compilation extends Tapable {
9494 this . dependencyTemplates = new Map ( ) ;
9595 this . dependencyTemplates . set ( "hash" , "" ) ;
9696 this . childrenCounters = { } ;
97+
98+ this . _buildingModules = new Map ( ) ;
99+ this . _rebuildingModules = new Map ( ) ;
97100 }
98101
99102 getStats ( ) {
@@ -107,29 +110,29 @@ class Compilation extends Tapable {
107110
108111 addModule ( module , cacheGroup ) {
109112 const identifier = module . identifier ( ) ;
110- if ( this . _modules [ identifier ] ) {
113+ if ( this . _modules . get ( identifier ) ) {
111114 return false ;
112115 }
113116 const cacheName = ( cacheGroup || "m" ) + identifier ;
114117 if ( this . cache && this . cache [ cacheName ] ) {
115118 const cacheModule = this . cache [ cacheName ] ;
116119
117120 let rebuild = true ;
118- if ( ! cacheModule . error && cacheModule . cacheable && this . fileTimestamps && this . contextTimestamps ) {
121+ if ( this . fileTimestamps && this . contextTimestamps ) {
119122 rebuild = cacheModule . needRebuild ( this . fileTimestamps , this . contextTimestamps ) ;
120123 }
121124
122125 if ( ! rebuild ) {
123126 cacheModule . disconnect ( ) ;
124- this . _modules [ identifier ] = cacheModule ;
127+ this . _modules . set ( identifier , cacheModule ) ;
125128 this . modules . push ( cacheModule ) ;
126129 cacheModule . errors . forEach ( err => this . errors . push ( err ) , this ) ;
127130 cacheModule . warnings . forEach ( err => this . warnings . push ( err ) , this ) ;
128131 return cacheModule ;
129132 }
133+ module . unbuild ( ) ;
130134 }
131- module . unbuild ( ) ;
132- this . _modules [ identifier ] = module ;
135+ this . _modules . set ( identifier , module ) ;
133136 if ( this . cache ) {
134137 this . cache [ cacheName ] = module ;
135138 }
@@ -139,22 +142,36 @@ class Compilation extends Tapable {
139142
140143 getModule ( module ) {
141144 const identifier = module . identifier ( ) ;
142- return this . _modules [ identifier ] ;
145+ return this . _modules . get ( identifier ) ;
143146 }
144147
145148 findModule ( identifier ) {
146- return this . _modules [ identifier ] ;
149+ return this . _modules . get ( identifier ) ;
150+ }
151+
152+ waitForBuildingFinished ( module , callback ) {
153+ let callbackList = this . _buildingModules . get ( module ) ;
154+ if ( callbackList ) {
155+ callbackList . push ( ( ) => callback ( ) ) ;
156+ } else {
157+ process . nextTick ( callback ) ;
158+ }
147159 }
148160
149161 buildModule ( module , optional , origin , dependencies , thisCallback ) {
150162 this . applyPlugins1 ( "build-module" , module ) ;
151- if ( module . building ) return module . building . push ( thisCallback ) ;
152- const building = module . building = [ thisCallback ] ;
153-
154- function callback ( err ) {
155- module . building = undefined ;
156- building . forEach ( cb => cb ( err ) ) ;
163+ let callbackList = this . _buildingModules . get ( module ) ;
164+ if ( callbackList ) {
165+ callbackList . push ( thisCallback ) ;
166+ return ;
157167 }
168+ this . _buildingModules . set ( module , callbackList = [ thisCallback ] ) ;
169+
170+ const callback = err => {
171+ this . _buildingModules . delete ( module ) ;
172+ callbackList . forEach ( cb => cb ( err ) ) ;
173+ } ;
174+
158175 module . build ( this . options , this , this . resolvers . normal , this . inputFileSystem , ( error ) => {
159176 const errors = module . errors ;
160177 for ( let indexError = 0 ; indexError < errors . length ; indexError ++ ) {
@@ -259,7 +276,7 @@ class Compilation extends Tapable {
259276 let afterFactory ;
260277
261278 function isOptional ( ) {
262- return dependencies . filter ( d => ! d . optional ) . length === 0 ;
279+ return dependencies . every ( d => d . optional ) ;
263280 }
264281
265282 function errorOrWarningAndCallback ( err ) {
@@ -294,16 +311,11 @@ class Compilation extends Tapable {
294311 dependentModule . profile . factory = afterFactory - start ;
295312 }
296313
297- dependentModule . issuer = module ;
298314 const newModule = _this . addModule ( dependentModule , cacheGroup ) ;
299315
300316 if ( ! newModule ) { // from cache
301317 dependentModule = _this . getModule ( dependentModule ) ;
302318
303- if ( dependentModule . optional ) {
304- dependentModule . optional = isOptional ( ) ;
305- }
306-
307319 iterationDependencies ( dependencies ) ;
308320
309321 if ( _this . profile ) {
@@ -317,16 +329,16 @@ class Compilation extends Tapable {
317329 }
318330
319331 semaphore . release ( ) ;
320- return process . nextTick ( callback ) ;
332+ _this . waitForBuildingFinished ( dependentModule , callback ) ;
333+ return ;
321334 }
322335
323336 if ( newModule instanceof Module ) {
324337 if ( _this . profile ) {
325338 newModule . profile = dependentModule . profile ;
326339 }
327340
328- newModule . optional = isOptional ( ) ;
329- newModule . issuer = dependentModule . issuer ;
341+ newModule . issuer = module ;
330342 dependentModule = newModule ;
331343
332344 iterationDependencies ( dependencies ) ;
@@ -344,7 +356,7 @@ class Compilation extends Tapable {
344356 }
345357 }
346358
347- dependentModule . optional = isOptional ( ) ;
359+ dependentModule . issuer = module ;
348360
349361 iterationDependencies ( dependencies ) ;
350362
@@ -436,13 +448,20 @@ class Compilation extends Tapable {
436448
437449 onModule ( module ) ;
438450
451+ dependency . module = module ;
452+ module . addReason ( null , dependency ) ;
453+
439454 if ( this . profile ) {
440455 const afterBuilding = Date . now ( ) ;
441456 module . profile . building = afterBuilding - afterFactory ;
442457 }
443458
444459 this . semaphore . release ( ) ;
445- return callback ( null , module ) ;
460+ this . waitForBuildingFinished ( module , err => {
461+ if ( err ) return callback ( err ) ;
462+ callback ( null , module ) ;
463+ } ) ;
464+ return ;
446465 }
447466
448467 if ( result instanceof Module ) {
@@ -454,12 +473,18 @@ class Compilation extends Tapable {
454473
455474 onModule ( module ) ;
456475
476+ dependency . module = module ;
477+ module . addReason ( null , dependency ) ;
478+
457479 moduleReady . call ( this ) ;
458480 return ;
459481 }
460482
461483 onModule ( module ) ;
462484
485+ dependency . module = module ;
486+ module . addReason ( null , dependency ) ;
487+
463488 this . buildModule ( module , false , null , null , ( err ) => {
464489 if ( err ) {
465490 this . semaphore . release ( ) ;
@@ -496,9 +521,7 @@ class Compilation extends Tapable {
496521 this . preparedChunks . push ( slot ) ;
497522 this . _addModuleChain ( context , entry , ( module ) => {
498523
499- entry . module = module ;
500524 this . entries . push ( module ) ;
501- module . issuer = null ;
502525
503526 } , ( err , module ) => {
504527 if ( err ) {
@@ -519,39 +542,35 @@ class Compilation extends Tapable {
519542 this . _addModuleChain ( context , dependency , module => {
520543
521544 module . prefetched = true ;
522- module . issuer = null ;
523545
524546 } , callback ) ;
525547 }
526548
527549 rebuildModule ( module , thisCallback ) {
528- if ( module . variables . length || module . blocks . length )
529- throw new Error ( "Cannot rebuild a complex module with variables or blocks" ) ;
530- if ( module . rebuilding ) {
531- return module . rebuilding . push ( thisCallback ) ;
550+ let callbackList = this . _rebuildingModules . get ( module ) ;
551+ if ( callbackList ) {
552+ callbackList . push ( thisCallback ) ;
553+ return ;
532554 }
533- const rebuilding = module . rebuilding = [ thisCallback ] ;
555+ this . _rebuildingModules . set ( module , callbackList = [ thisCallback ] ) ;
534556
535- function callback ( err ) {
536- module . rebuilding = undefined ;
537- rebuilding . forEach ( cb => cb ( err ) ) ;
538- }
539- const deps = module . dependencies . slice ( ) ;
557+ const callback = err => {
558+ this . _rebuildingModules . delete ( module ) ;
559+ callbackList . forEach ( cb => cb ( err ) ) ;
560+ } ;
561+
562+ const oldDependencies = module . dependencies . slice ( ) ;
563+ const oldVariables = module . variables . slice ( ) ;
564+ const oldBlocks = module . blocks . slice ( ) ;
540565 this . buildModule ( module , false , module , null , ( err ) => {
541566 if ( err ) return callback ( err ) ;
542567
543568 this . processModuleDependencies ( module , ( err ) => {
544569 if ( err ) return callback ( err ) ;
545- deps . forEach ( d => {
546- if ( d . module && d . module . removeReason ( module , d ) ) {
547- module . forEachChunk ( chunk => {
548- if ( ! d . module . hasReasonForChunk ( chunk ) ) {
549- if ( d . module . removeChunk ( chunk ) ) {
550- this . removeChunkFromDependencies ( d . module , chunk ) ;
551- }
552- }
553- } ) ;
554- }
570+ this . removeReasonsOfDependencyBlock ( module , {
571+ dependencies : oldDependencies ,
572+ variables : oldVariables ,
573+ blocks : oldBlocks
555574 } ) ;
556575 callback ( ) ;
557576 } ) ;
@@ -1084,16 +1103,46 @@ class Compilation extends Tapable {
10841103 }
10851104 }
10861105
1087- removeChunkFromDependencies ( block , chunk ) {
1106+ removeReasonsOfDependencyBlock ( module , block ) {
10881107 const iteratorDependency = d => {
10891108 if ( ! d . module ) {
10901109 return ;
10911110 }
1092- if ( ! d . module . hasReasonForChunk ( chunk ) ) {
1093- if ( d . module . removeChunk ( chunk ) ) {
1094- this . removeChunkFromDependencies ( d . module , chunk ) ;
1095- }
1111+ if ( d . module . removeReason ( module , d ) ) {
1112+ d . module . forEachChunk ( chunk => this . patchChunksAfterReasonRemoval ( d . module , chunk ) ) ;
1113+ }
1114+ } ;
1115+
1116+ if ( block . blocks ) {
1117+ iterationOfArrayCallback ( block . blocks , block => this . removeReasonsOfDependencyBlock ( module , block ) ) ;
1118+ }
1119+
1120+ if ( block . dependencies ) {
1121+ iterationOfArrayCallback ( block . dependencies , iteratorDependency ) ;
1122+ }
1123+
1124+ if ( block . variables ) {
1125+ iterationBlockVariable ( block . variables , iteratorDependency ) ;
1126+ }
1127+ }
1128+
1129+ patchChunksAfterReasonRemoval ( module , chunk ) {
1130+ if ( ! module . hasReasons ( ) ) {
1131+ this . removeReasonsOfDependencyBlock ( module , module ) ;
1132+ }
1133+ if ( ! module . hasReasonForChunk ( chunk ) ) {
1134+ if ( module . removeChunk ( chunk ) ) {
1135+ this . removeChunkFromDependencies ( module , chunk ) ;
1136+ }
1137+ }
1138+ }
1139+
1140+ removeChunkFromDependencies ( block , chunk ) {
1141+ const iteratorDependency = d => {
1142+ if ( ! d . module ) {
1143+ return ;
10961144 }
1145+ this . patchChunksAfterReasonRemoval ( d . module , chunk ) ;
10971146 } ;
10981147
10991148 const blocks = block . blocks ;
0 commit comments