From 9df98e65f842cf3acae09cbdd969966f42d64469 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sat, 14 Oct 2017 18:40:54 +0200 Subject: update dependencies --- node_modules/webpack/lib/Compilation.js | 191 ++++++++++++++++++++++++-------- 1 file changed, 144 insertions(+), 47 deletions(-) (limited to 'node_modules/webpack/lib/Compilation.js') diff --git a/node_modules/webpack/lib/Compilation.js b/node_modules/webpack/lib/Compilation.js index b59c0eb53..72b195745 100644 --- a/node_modules/webpack/lib/Compilation.js +++ b/node_modules/webpack/lib/Compilation.js @@ -232,7 +232,10 @@ class Compilation extends Tapable { callback(); }; - _this.semaphore.acquire(() => { + const semaphore = _this.semaphore; + semaphore.acquire(() => { + if(_this === null) return semaphore.release(); + const factory = item[0]; factory.create({ contextInfo: { @@ -242,6 +245,8 @@ class Compilation extends Tapable { context: module.context, dependencies: dependencies }, function factoryCallback(err, dependentModule) { + if(_this === null) return semaphore.release(); + let afterFactory; function isOptional() { @@ -265,11 +270,11 @@ class Compilation extends Tapable { } if(err) { - _this.semaphore.release(); + semaphore.release(); return errorOrWarningAndCallback(new ModuleNotFoundError(module, err, dependencies)); } if(!dependentModule) { - _this.semaphore.release(); + semaphore.release(); return process.nextTick(callback); } if(_this.profile) { @@ -302,7 +307,7 @@ class Compilation extends Tapable { } } - _this.semaphore.release(); + semaphore.release(); return process.nextTick(callback); } @@ -322,7 +327,7 @@ class Compilation extends Tapable { module.profile.building = afterBuilding - afterFactory; } - _this.semaphore.release(); + semaphore.release(); if(recursive) { return process.nextTick(_this.processModuleDependencies.bind(_this, dependentModule, callback)); } else { @@ -335,8 +340,10 @@ class Compilation extends Tapable { iterationDependencies(dependencies); _this.buildModule(dependentModule, isOptional(), module, dependencies, err => { + if(_this === null) return semaphore.release(); + if(err) { - _this.semaphore.release(); + semaphore.release(); return errorOrWarningAndCallback(err); } @@ -345,7 +352,7 @@ class Compilation extends Tapable { dependentModule.profile.building = afterBuilding - afterFactory; } - _this.semaphore.release(); + semaphore.release(); if(recursive) { _this.processModuleDependencies(dependentModule, callback); } else { @@ -578,8 +585,8 @@ class Compilation extends Tapable { chunk.entryModule = module; self.assignIndex(module); self.assignDepth(module); - self.processDependenciesBlockForChunk(module, chunk); }); + self.processDependenciesBlocksForChunks(self.chunks.slice()); self.sortModules(self.modules); self.applyPlugins0("optimize"); @@ -846,62 +853,90 @@ class Compilation extends Tapable { } } - processDependenciesBlockForChunk(module, chunk) { - let block = module; - const initialChunk = chunk; + // This method creates the Chunk graph from the Module graph + processDependenciesBlocksForChunks(inputChunks) { + // Process is splitting into two parts: + // Part one traverse the module graph and builds a very basic chunks graph + // in chunkDependencies. + // Part two traverse every possible way through the basic chunk graph and + // tracks the available modules. While traversing it connects chunks with + // eachother and Blocks with Chunks. It stops traversing when all modules + // for a chunk are already available. So it doesn't connect unneeded chunks. + const chunkDependencies = new Map(); // Map> + const allCreatedChunks = new Set(); + + // PART ONE + const blockChunks = new Map(); + + // Start with the provided modules/chunks + const queue = inputChunks.map(chunk => ({ + block: chunk.entryModule, + chunk: chunk + })); + + let block, chunk; + + // For each async Block in graph const iteratorBlock = b => { - let c; - if(!b.chunks) { + // 1. We create a chunk for this Block + // but only once (blockChunks map) + let c = blockChunks.get(b); + if(c === undefined) { c = this.addChunk(b.chunkName, b.module, b.loc); - b.chunks = [c]; - c.addBlock(b); - } else { - c = b.chunks[0]; + blockChunks.set(b, c); + allCreatedChunks.add(c); + // We initialize the chunks property + // this is later filled with the chunk when needed + b.chunks = []; } + + // 2. We store the Block+Chunk mapping as dependency for the chunk let deps = chunkDependencies.get(chunk); if(!deps) chunkDependencies.set(chunk, deps = []); deps.push({ - chunk: c, - module + block: b, + chunk: c }); + + // 3. We enqueue the DependenciesBlock for traversal queue.push({ block: b, - module: null, chunk: c }); }; + // For each Dependency in the graph const iteratorDependency = d => { + // We skip Dependencies without Module pointer if(!d.module) { return; } + // We skip weak Dependencies if(d.weak) { return; } + // We connect Module and Chunk when not already done if(chunk.addModule(d.module)) { d.module.addChunk(chunk); + + // And enqueue the Module for traversal queue.push({ block: d.module, - module: d.module, chunk }); } }; - const queue = [{ - block, - module, - chunk - }]; - + // Iterative traversal of the Module graph + // Recursive would be simpler to write but could result in Stack Overflows while(queue.length) { const queueItem = queue.pop(); block = queueItem.block; - module = queueItem.module; chunk = queueItem.chunk; + // Traverse all variables, Dependencies and Blocks if(block.variables) { iterationBlockVariable(block.variables, iteratorDependency); } @@ -915,46 +950,108 @@ class Compilation extends Tapable { } } - chunk = initialChunk; - let chunks = new Set(); - const queue2 = [{ + // PART TWO + + let availableModules; + let newAvailableModules; + const queue2 = inputChunks.map(chunk => ({ chunk, - chunks - }]; + availableModules: new Set() + })); - const filterFn = dep => { - if(chunks.has(dep.chunk)) return false; - for(const chunk of chunks) { - if(chunk.containsModule(dep.module)) + // Helper function to check if all modules of a chunk are available + const areModulesAvailable = (chunk, availableModules) => { + for(const module of chunk.modulesIterable) { + if(!availableModules.has(module)) return false; } return true; }; + // For each edge in the basic chunk graph + const filterFn = dep => { + // Filter egdes that are not needed because all modules are already available + // This also filters circular dependencies in the chunks graph + const depChunk = dep.chunk; + if(areModulesAvailable(depChunk, newAvailableModules)) + return false; // break all modules are already available + return true; + }; + + const minAvailableModulesMap = new Map(); + + // Iterative traversing of the basic chunk graph while(queue2.length) { const queueItem = queue2.pop(); chunk = queueItem.chunk; - chunks = queueItem.chunks; + availableModules = queueItem.availableModules; + + // 1. Get minimal available modules + // It doesn't make sense to traverse a chunk again with more available modules. + // This step calculates the minimal available modules and skips traversal when + // the list didn't shrink. + let minAvailableModules = minAvailableModulesMap.get(chunk); + if(minAvailableModules === undefined) { + minAvailableModulesMap.set(chunk, new Set(availableModules)); + } else { + let deletedModules = false; + for(const m of minAvailableModules) { + if(!availableModules.has(m)) { + minAvailableModules.delete(m); + deletedModules = true; + } + } + if(!deletedModules) + continue; + } + // 2. Get the edges at this point of the graph const deps = chunkDependencies.get(chunk); if(!deps) continue; + if(deps.length === 0) continue; - const depsFiltered = deps.filter(filterFn); + // 3. Create a new Set of available modules at this points + newAvailableModules = new Set(availableModules); + for(const m of chunk.modulesIterable) + newAvailableModules.add(m); - for(let i = 0; i < depsFiltered.length; i++) { - const dep = depsFiltered[i]; + // 4. Filter edges with available modules + const filteredDeps = deps.filter(filterFn); + + // 5. Foreach remaining edge + const nextChunks = new Set(); + for(let i = 0; i < filteredDeps.length; i++) { + const dep = filteredDeps[i]; const depChunk = dep.chunk; - chunk.addChunk(depChunk); - depChunk.addParent(chunk); + const depBlock = dep.block; + + // 6. Connnect block with chunk + if(depChunk.addBlock(depBlock)) { + depBlock.chunks.push(depChunk); + } + + // 7. Connect chunk with parent + if(chunk.addChunk(depChunk)) { + depChunk.addParent(chunk); + } - const newChunks = depsFiltered.length > 1 ? new Set(chunks) : chunks; - newChunks.add(chunk); + nextChunks.add(depChunk); + } + + // 8. Enqueue further traversal + for(const nextChunk of nextChunks) { queue2.push({ - chunk: depChunk, - chunks: newChunks + chunk: nextChunk, + availableModules: newAvailableModules }); } } + + // Remove all unconnected chunks + for(const chunk of allCreatedChunks) { + if(chunk.parents.length === 0) + chunk.remove("unconnected"); + } } removeChunkFromDependencies(block, chunk) { -- cgit v1.2.3