mirror of https://github.com/webpack/webpack.git
improve module dependency processing performance
This commit is contained in:
parent
3b2443c0ba
commit
a060126e49
|
|
@ -1375,84 +1375,114 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
|
|||
* @returns {void}
|
||||
*/
|
||||
_processModuleDependencies(module, callback) {
|
||||
const dependencies = new Map();
|
||||
|
||||
/**
|
||||
* @type {Array<{factory: ModuleFactory, dependencies: Dependency[], originModule: Module|null}>}
|
||||
*/
|
||||
const sortedDependencies = [];
|
||||
|
||||
let currentBlock = module;
|
||||
/** @type {DependenciesBlock} */
|
||||
let currentBlock;
|
||||
|
||||
/** @type {Map<ModuleFactory, Map<string, Dependency[]>>} */
|
||||
let dependencies;
|
||||
/** @type {DepConstructor} */
|
||||
let factoryCacheKey;
|
||||
/** @type {ModuleFactory} */
|
||||
let factoryCacheKey2;
|
||||
/** @type {Map<string, Dependency[]>} */
|
||||
let factoryCacheValue;
|
||||
let factoryCacheValue2;
|
||||
let listCacheKey;
|
||||
/** @type {string} */
|
||||
let listCacheKey1;
|
||||
/** @type {string} */
|
||||
let listCacheKey2;
|
||||
/** @type {Dependency[]} */
|
||||
let listCacheValue;
|
||||
|
||||
/**
|
||||
* @param {Dependency} dep dependency
|
||||
* @returns {void}
|
||||
*/
|
||||
const processDependency = dep => {
|
||||
this.moduleGraph.setParents(dep, currentBlock, module);
|
||||
const resourceIdent = dep.getResourceIdentifier();
|
||||
if (resourceIdent) {
|
||||
// Here webpack is using heuristic that assumes
|
||||
// mostly esm dependencies would be used
|
||||
// so we don't allocate extra string for them
|
||||
if (resourceIdent !== undefined && resourceIdent !== null) {
|
||||
const category = dep.category;
|
||||
const cacheKey =
|
||||
category === esmDependencyCategory
|
||||
? resourceIdent
|
||||
: `${category}${resourceIdent}`;
|
||||
const constructor = dep.constructor;
|
||||
let innerMap;
|
||||
let factory;
|
||||
const constructor = /** @type {DepConstructor} */ (dep.constructor);
|
||||
if (factoryCacheKey === constructor) {
|
||||
innerMap = factoryCacheValue;
|
||||
if (listCacheKey === cacheKey) {
|
||||
// Fast path 1: same constructor as prev item
|
||||
if (listCacheKey1 === category && listCacheKey2 === resourceIdent) {
|
||||
// Super fast path 1: also same resource
|
||||
listCacheValue.push(dep);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
factory = this.dependencyFactories.get(constructor);
|
||||
const factory = this.dependencyFactories.get(constructor);
|
||||
if (factory === undefined) {
|
||||
throw new Error(
|
||||
`No module factory available for dependency type: ${constructor.name}`
|
||||
);
|
||||
}
|
||||
innerMap = dependencies.get(factory);
|
||||
if (innerMap === undefined) {
|
||||
dependencies.set(factory, (innerMap = new Map()));
|
||||
if (factoryCacheKey2 === factory) {
|
||||
// Fast path 2: same factory as prev item
|
||||
factoryCacheKey = constructor;
|
||||
if (listCacheKey1 === category && listCacheKey2 === resourceIdent) {
|
||||
// Super fast path 2: also same resource
|
||||
listCacheValue.push(dep);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Slow path
|
||||
if (factoryCacheKey2 !== undefined) {
|
||||
// Archive last cache entry
|
||||
if (dependencies === undefined) dependencies = new Map();
|
||||
dependencies.set(factoryCacheKey2, factoryCacheValue);
|
||||
factoryCacheValue = dependencies.get(factory);
|
||||
if (factoryCacheValue === undefined) {
|
||||
factoryCacheValue = new Map();
|
||||
}
|
||||
} else {
|
||||
factoryCacheValue = new Map();
|
||||
}
|
||||
factoryCacheKey = constructor;
|
||||
factoryCacheKey2 = factory;
|
||||
}
|
||||
factoryCacheKey = constructor;
|
||||
factoryCacheValue = innerMap;
|
||||
factoryCacheValue2 = factory;
|
||||
}
|
||||
let list = innerMap.get(cacheKey);
|
||||
// Here webpack is using heuristic that assumes
|
||||
// mostly esm dependencies would be used
|
||||
// so we don't allocate extra string for them
|
||||
const cacheKey =
|
||||
category === esmDependencyCategory
|
||||
? resourceIdent
|
||||
: `${category}${resourceIdent}`;
|
||||
let list = factoryCacheValue.get(cacheKey);
|
||||
if (list === undefined) {
|
||||
innerMap.set(cacheKey, (list = []));
|
||||
factoryCacheValue.set(cacheKey, (list = []));
|
||||
sortedDependencies.push({
|
||||
factory: factoryCacheValue2,
|
||||
factory: factoryCacheKey2,
|
||||
dependencies: list,
|
||||
originModule: module
|
||||
});
|
||||
}
|
||||
list.push(dep);
|
||||
listCacheKey = cacheKey;
|
||||
listCacheKey1 = category;
|
||||
listCacheKey2 = resourceIdent;
|
||||
listCacheValue = list;
|
||||
}
|
||||
};
|
||||
|
||||
const processDependenciesBlock = block => {
|
||||
if (block.dependencies) {
|
||||
currentBlock = block;
|
||||
for (const dep of block.dependencies) processDependency(dep);
|
||||
}
|
||||
if (block.blocks) {
|
||||
for (const b of block.blocks) processDependenciesBlock(b);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
processDependenciesBlock(module);
|
||||
/** @type {DependenciesBlock[]} */
|
||||
const queue = [module];
|
||||
do {
|
||||
const block = queue.pop();
|
||||
if (block.dependencies) {
|
||||
currentBlock = block;
|
||||
for (const dep of block.dependencies) processDependency(dep);
|
||||
}
|
||||
if (block.blocks) {
|
||||
for (const b of block.blocks) queue.push(b);
|
||||
}
|
||||
} while (queue.length !== 0);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue