Skip to content

Commit

Permalink
Merge pull request #12760 from webpack/performance/module-concatenation
Browse files Browse the repository at this point in the history
  • Loading branch information
sokra committed Feb 23, 2021
2 parents 63c14cc + 5c42b91 commit 732179e
Show file tree
Hide file tree
Showing 11 changed files with 318 additions and 182 deletions.
6 changes: 3 additions & 3 deletions lib/CaseSensitiveModulesWarning.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ const createModulesListMessage = (modules, moduleGraph) => {
.map(m => {
let message = `* ${m.identifier()}`;
const validReasons = Array.from(
moduleGraph.getIncomingConnections(m)
).filter(reason => reason.originModule);
moduleGraph.getIncomingConnectionsByOriginModule(m).keys()
).filter(x => x);

if (validReasons.length > 0) {
message += `\n Used by ${validReasons.length} module(s), i. e.`;
message += `\n ${validReasons[0].originModule.identifier()}`;
message += `\n ${validReasons[0].identifier()}`;
}
return message;
})
Expand Down
18 changes: 13 additions & 5 deletions lib/ChunkGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ const getArray = set => {
return Array.from(set);
};

/**
* @param {SortableSet<Chunk>} chunks the chunks
* @returns {RuntimeSpecSet} runtimes
*/
const getModuleRuntimes = chunks => {
const runtimes = new RuntimeSpecSet();
for (const chunk of chunks) {
runtimes.add(chunk.runtime);
}
return runtimes;
};

/**
* @param {SortableSet<Module>} set the set
* @returns {Map<string, SortableSet<Module>>} modules by source type
Expand Down Expand Up @@ -510,11 +522,7 @@ class ChunkGraph {
*/
getModuleRuntimes(module) {
const cgm = this._getChunkGraphModule(module);
const runtimes = new RuntimeSpecSet();
for (const chunk of cgm.chunks) {
runtimes.add(chunk.runtime);
}
return runtimes;
return cgm.chunks.getFromUnorderedCache(getModuleRuntimes);
}

/**
Expand Down
8 changes: 5 additions & 3 deletions lib/Module.js
Original file line number Diff line number Diff line change
Expand Up @@ -631,9 +631,11 @@ class Module extends DependenciesBlock {
*/
hasReasonForChunk(chunk, moduleGraph, chunkGraph) {
// check for each reason if we need the chunk
for (const connection of moduleGraph.getIncomingConnections(this)) {
if (!connection.isTargetActive(chunk.runtime)) continue;
const fromModule = connection.originModule;
for (const [
fromModule,
connections
] of moduleGraph.getIncomingConnectionsByOriginModule(this)) {
if (!connections.some(c => c.isTargetActive(chunk.runtime))) continue;
for (const originChunk of chunkGraph.getModuleChunksIterable(
fromModule
)) {
Expand Down
48 changes: 42 additions & 6 deletions lib/ModuleGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
const util = require("util");
const ExportsInfo = require("./ExportsInfo");
const ModuleGraphConnection = require("./ModuleGraphConnection");
const SortableSet = require("./util/SortableSet");

/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
/** @typedef {import("./Dependency")} Dependency */
/** @typedef {import("./ExportsInfo").ExportInfo} ExportInfo */
/** @typedef {import("./Module")} Module */
/** @typedef {import("./ModuleProfile")} ModuleProfile */
/** @typedef {import("./RequestShortener")} RequestShortener */
/** @template T @typedef {import("./util/SortableSet")<T>} SortableSet<t> */
/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */

/**
Expand All @@ -26,10 +26,40 @@ const ModuleGraphConnection = require("./ModuleGraphConnection");

const EMPTY_ARRAY = [];

/**
* @param {SortableSet<ModuleGraphConnection>} set input
* @returns {readonly Map<Module, readonly ModuleGraphConnection[]>} mapped by origin module
*/
const getConnectionsByOriginModule = set => {
const map = new Map();
/** @type {Module | 0} */
let lastModule = 0;
/** @type {ModuleGraphConnection[]} */
let lastList = undefined;
for (const connection of set) {
const { originModule } = connection;
if (lastModule === originModule) {
lastList.push(connection);
} else {
lastModule = originModule;
const list = map.get(originModule);
if (list !== undefined) {
lastList = list;
list.push(connection);
} else {
const list = [connection];
lastList = list;
map.set(originModule, list);
}
}
}
return map;
};

class ModuleGraphModule {
constructor() {
/** @type {Set<ModuleGraphConnection>} */
this.incomingConnections = new Set();
/** @type {SortableSet<ModuleGraphConnection>} */
this.incomingConnections = new SortableSet();
/** @type {Set<ModuleGraphConnection> | undefined} */
this.outgoingConnections = undefined;
/** @type {Module | null} */
Expand Down Expand Up @@ -319,9 +349,6 @@ class ModuleGraph {
newConnections.add(newConnection);
if (newConnection.module !== undefined) {
const otherMgm = this._getModuleGraphModule(newConnection.module);
if (otherMgm.incomingConnections === undefined) {
otherMgm.incomingConnections = new Set();
}
otherMgm.incomingConnections.add(newConnection);
}
}
Expand Down Expand Up @@ -402,6 +429,15 @@ class ModuleGraph {
return connections === undefined ? EMPTY_ARRAY : connections;
}

/**
* @param {Module} module the module
* @returns {readonly Map<Module, readonly ModuleGraphConnection[]>} reasons why a module is included, in a map by source module
*/
getIncomingConnectionsByOriginModule(module) {
const connections = this._getModuleGraphModule(module).incomingConnections;
return connections.getFromUnorderedCache(getConnectionsByOriginModule);
}

/**
* @param {Module} module the module
* @returns {ModuleProfile | null} the module profile
Expand Down
4 changes: 2 additions & 2 deletions lib/ModuleGraphConnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ const intersectConnectionStates = (a, b) => {

class ModuleGraphConnection {
/**
* @param {Module|undefined} originModule the referencing module
* @param {Dependency|undefined} dependency the referencing dependency
* @param {Module|null} originModule the referencing module
* @param {Dependency|null} dependency the referencing dependency
* @param {Module} module the referenced module
* @param {string=} explanation some extra detail
* @param {boolean=} weak the reference is weak
Expand Down
16 changes: 10 additions & 6 deletions lib/async-modules/InferAsyncModulesPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,18 @@ class InferAsyncModulesPlugin {
}
for (const module of queue) {
moduleGraph.setAsync(module);
const connections = moduleGraph.getIncomingConnections(module);
for (const connection of connections) {
const dep = connection.dependency;
for (const [
originModule,
connections
] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
if (
dep instanceof HarmonyImportDependency &&
connection.isTargetActive(undefined)
connections.some(
c =>
c.dependency instanceof HarmonyImportDependency &&
c.isTargetActive(undefined)
)
) {
queue.add(connection.originModule);
queue.add(originModule);
}
}
}
Expand Down
45 changes: 28 additions & 17 deletions lib/ids/OccurrenceModuleIdsPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,40 +66,51 @@ class OccurrenceModuleIdsPlugin {
}

/**
* @param {Iterable<ModuleGraphConnection>} connections connections
* @param {Module} module module
* @returns {number} count of occurs
*/
const countOccursInEntry = connections => {
const countOccursInEntry = module => {
let sum = 0;
for (const c of connections) {
if (!c.isTargetActive(undefined)) continue;
if (!c.originModule) continue;
sum += initialChunkChunkMap.get(c.originModule);
for (const [
originModule,
connections
] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
if (!originModule) continue;
if (!connections.some(c => c.isTargetActive(undefined))) continue;
sum += initialChunkChunkMap.get(originModule);
}
return sum;
};

/**
* @param {Iterable<ModuleGraphConnection>} connections connections
* @param {Module} module module
* @returns {number} count of occurs
*/
const countOccurs = connections => {
const countOccurs = module => {
let sum = 0;
for (const c of connections) {
if (!c.isTargetActive(undefined)) continue;
if (!c.originModule) continue;
if (!c.dependency) continue;
const factor = c.dependency.getNumberOfIdOccurrences();
if (factor === 0) continue;
sum += factor * chunkGraph.getNumberOfModuleChunks(c.originModule);
for (const [
originModule,
connections
] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
if (!originModule) continue;
const chunkModules = chunkGraph.getNumberOfModuleChunks(
originModule
);
for (const c of connections) {
if (!c.isTargetActive(undefined)) continue;
if (!c.dependency) continue;
const factor = c.dependency.getNumberOfIdOccurrences();
if (factor === 0) continue;
sum += factor * chunkModules;
}
}
return sum;
};

if (prioritiseInitial) {
for (const m of modulesInOccurrenceOrder) {
const result =
countOccursInEntry(moduleGraph.getIncomingConnections(m)) +
countOccursInEntry(m) +
initialChunkChunkMap.get(m) +
entryCountMap.get(m);
occursInInitialChunksMap.set(m, result);
Expand All @@ -108,7 +119,7 @@ class OccurrenceModuleIdsPlugin {

for (const m of modules) {
const result =
countOccurs(moduleGraph.getIncomingConnections(m)) +
countOccurs(m) +
chunkGraph.getNumberOfModuleChunks(m) +
entryCountMap.get(m);
occursInAllChunksMap.set(m, result);
Expand Down
10 changes: 5 additions & 5 deletions lib/javascript/JavascriptModulesPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -901,12 +901,12 @@ class JavascriptModulesPlugin {
if (
result.allowInlineStartup &&
someInIterable(
moduleGraph.getIncomingConnections(entryModule),
c =>
c.originModule &&
c.isTargetActive(chunk.runtime) &&
moduleGraph.getIncomingConnectionsByOriginModule(entryModule),
([originModule, connections]) =>
originModule &&
connections.some(c => c.isTargetActive(chunk.runtime)) &&
someInIterable(
chunkGraph.getModuleRuntimes(c.originModule),
chunkGraph.getModuleRuntimes(originModule),
runtime =>
intersectRuntime(runtime, chunk.runtime) !== undefined
)
Expand Down

0 comments on commit 732179e

Please sign in to comment.