Skip to content

Commit 50fe2e7

Browse files
committed
add Compilation.getDependencyReference and hooks to override it
expose DependencyReference class
1 parent e1f0a66 commit 50fe2e7

File tree

11 files changed

+159
-37
lines changed

11 files changed

+159
-37
lines changed

lib/Compilation.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ const Queue = require("./util/Queue");
3636
const SortableSet = require("./util/SortableSet");
3737
const GraphHelpers = require("./GraphHelpers");
3838

39+
/** @typedef {import("./Module")} Module */
40+
/** @typedef {import("./dependencies/DependencyReference")} DependencyReference */
41+
/** @typedef {import("./Dependency")} Dependency */
42+
3943
const byId = (a, b) => {
4044
if (a.id < b.id) return -1;
4145
if (a.id > b.id) return 1;
@@ -104,6 +108,13 @@ class Compilation extends Tapable {
104108
failedModule: new SyncHook(["module", "error"]),
105109
succeedModule: new SyncHook(["module"]),
106110

111+
/** @type {SyncWaterfallHook<DependencyReference, Dependency, Module>} */
112+
dependencyReference: new SyncWaterfallHook([
113+
"dependencyReference",
114+
"dependency",
115+
"module"
116+
]),
117+
107118
finishModules: new SyncHook(["modules"]),
108119
finishRebuildingModule: new SyncHook(["module"]),
109120

@@ -1175,6 +1186,19 @@ class Compilation extends Tapable {
11751186
}
11761187
}
11771188

1189+
/**
1190+
* @param {Module} module the module containing the dependency
1191+
* @param {Dependency} dependency the dependency
1192+
* @returns {DependencyReference} a reference for the dependency
1193+
*/
1194+
getDependencyReference(module, dependency) {
1195+
// TODO remove dep.getReference existance check in webpack 5
1196+
if (typeof dependency.getReference !== "function") return null;
1197+
const ref = dependency.getReference();
1198+
if (!ref) return null;
1199+
return this.hooks.dependencyReference.call(ref, dependency, module);
1200+
}
1201+
11781202
// This method creates the Chunk graph from the Module graph
11791203
processDependenciesBlocksForChunkGroups(inputChunkGroups) {
11801204
// Process is splitting into two parts:
@@ -1193,7 +1217,7 @@ class Compilation extends Tapable {
11931217

11941218
const iteratorDependency = d => {
11951219
// We skip Dependencies without Reference
1196-
const ref = d.getReference();
1220+
const ref = this.getDependencyReference(currentModule, d);
11971221
if (!ref) {
11981222
return;
11991223
}
@@ -1215,9 +1239,12 @@ class Compilation extends Tapable {
12151239
blockQueue.push(b);
12161240
};
12171241

1242+
/** @type {Module} */
1243+
let currentModule;
12181244
let block, blockQueue, blockInfoModules, blockInfoBlocks;
12191245
for (const module of this.modules) {
12201246
blockQueue = [module];
1247+
currentModule = module;
12211248
while (blockQueue.length > 0) {
12221249
block = blockQueue.pop();
12231250
blockInfoModules = new Set();

lib/FlagDependencyUsagePlugin.js

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
*/
55
"use strict";
66

7+
/** @typedef {import("./Module")} Module */
8+
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
9+
10+
/** @typedef {false | true | string[]} UsedExports */
11+
712
const addToSet = (a, b) => {
813
for (const item of b) {
914
if (!a.includes(item)) a.push(item);
@@ -54,44 +59,44 @@ class FlagDependencyUsagePlugin {
5459
return;
5560
}
5661

57-
queue.push([module, module.usedExports]);
62+
queue.push([module, module, module.usedExports]);
5863
};
5964

60-
const processDependenciesBlock = (depBlock, usedExports) => {
65+
const processDependenciesBlock = (module, depBlock, usedExports) => {
6166
for (const dep of depBlock.dependencies) {
62-
processDependency(dep);
67+
processDependency(module, dep);
6368
}
6469
for (const variable of depBlock.variables) {
6570
for (const dep of variable.dependencies) {
66-
processDependency(dep);
71+
processDependency(module, dep);
6772
}
6873
}
6974
for (const block of depBlock.blocks) {
70-
queue.push([block, usedExports]);
75+
queue.push([module, block, usedExports]);
7176
}
7277
};
7378

74-
const processDependency = dep => {
75-
// TODO remove dep.getReference existance check in webpack 5
76-
const reference = dep.getReference && dep.getReference();
79+
const processDependency = (module, dep) => {
80+
const reference = compilation.getDependencyReference(module, dep);
7781
if (!reference) return;
78-
const module = reference.module;
82+
const referenceModule = reference.module;
7983
const importedNames = reference.importedNames;
80-
const oldUsed = module.used;
81-
const oldUsedExports = module.usedExports;
84+
const oldUsed = referenceModule.used;
85+
const oldUsedExports = referenceModule.usedExports;
8286
if (
8387
!oldUsed ||
8488
(importedNames &&
8589
(!oldUsedExports || !isSubset(oldUsedExports, importedNames)))
8690
) {
87-
processModule(module, importedNames);
91+
processModule(referenceModule, importedNames);
8892
}
8993
};
9094

9195
for (const module of modules) {
9296
module.used = false;
9397
}
9498

99+
/** @type {[Module, DependenciesBlock, UsedExports][]} */
95100
const queue = [];
96101
for (const preparedEntrypoint of compilation._preparedEntrypoints) {
97102
if (preparedEntrypoint.module) {
@@ -101,7 +106,7 @@ class FlagDependencyUsagePlugin {
101106

102107
while (queue.length) {
103108
const queueItem = queue.pop();
104-
processDependenciesBlock(queueItem[0], queueItem[1]);
109+
processDependenciesBlock(queueItem[0], queueItem[1], queueItem[2]);
105110
}
106111
}
107112
);

lib/RuntimeTemplate.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ module.exports = class RuntimeTemplate {
265265

266266
if (exportName) {
267267
const used = module.isUsed(exportName);
268+
if (!used) {
269+
const comment = Template.toNormalComment(`unused export ${exportName}`);
270+
return `${comment} undefined`;
271+
}
268272
const comment =
269273
used !== exportName ? Template.toNormalComment(exportName) + " " : "";
270274
const access = `${importVar}[${comment}${JSON.stringify(used)}]`;

lib/optimize/ConcatenatedModule.js

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibi
2020
const createHash = require("../util/createHash");
2121

2222
/** @typedef {import("../Dependency")} Dependency */
23+
/** @typedef {import("../Compilation")} Compilation */
24+
25+
/**
26+
* @typedef {Object} ConcatenationEntry
27+
* @property {"concatenated" | "external"} type
28+
* @property {Module} module
29+
*/
2330

2431
const ensureNsObjSource = (
2532
info,
@@ -275,7 +282,7 @@ const getPathInAst = (ast, node) => {
275282
};
276283

277284
class ConcatenatedModule extends Module {
278-
constructor(rootModule, modules) {
285+
constructor(rootModule, modules, concatenationList) {
279286
super("javascript/esm", null);
280287
super.setChunks(rootModule._chunks);
281288

@@ -319,10 +326,9 @@ class ConcatenatedModule extends Module {
319326

320327
this.warnings = [];
321328
this.errors = [];
322-
this._orderedConcatenationList = this._createOrderedConcatenationList(
323-
rootModule,
324-
modulesSet
325-
);
329+
this._orderedConcatenationList =
330+
concatenationList ||
331+
ConcatenatedModule.createConcatenationList(rootModule, modulesSet, null);
326332
for (const info of this._orderedConcatenationList) {
327333
if (info.type === "concatenated") {
328334
const m = info.module;
@@ -409,7 +415,13 @@ class ConcatenatedModule extends Module {
409415
}, 0);
410416
}
411417

412-
_createOrderedConcatenationList(rootModule, modulesSet) {
418+
/**
419+
* @param {Module} rootModule the root of the concatenation
420+
* @param {Set<Module>} modulesSet a set of modules which should be concatenated
421+
* @param {Compilation} compilation the compilation context
422+
* @returns {ConcatenationEntry[]} concatenation list
423+
*/
424+
static createConcatenationList(rootModule, modulesSet, compilation) {
413425
const list = [];
414426
const set = new Set();
415427

@@ -423,7 +435,7 @@ class ConcatenatedModule extends Module {
423435
const references = module.dependencies
424436
.filter(dep => dep instanceof HarmonyImportDependency)
425437
.map(dep => {
426-
const ref = dep.getReference();
438+
const ref = compilation.getDependencyReference(module, dep);
427439
if (ref) map.set(ref, dep);
428440
return ref;
429441
})
@@ -432,7 +444,7 @@ class ConcatenatedModule extends Module {
432444
// TODO webpack 5: remove this hack, see also DependencyReference
433445
return references.map(ref => {
434446
const dep = map.get(ref);
435-
return () => dep.getReference().module;
447+
return () => compilation.getDependencyReference(module, dep).module;
436448
});
437449
};
438450

lib/optimize/ModuleConcatenationPlugin.js

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,9 @@ class ModuleConcatenationPlugin {
213213
const failureCache = new Map();
214214

215215
// try to add all imports
216-
for (const imp of this.getImports(currentRoot)) {
217-
const problem = this.tryToAdd(
216+
for (const imp of this._getImports(compilation, currentRoot)) {
217+
const problem = this._tryToAdd(
218+
compilation,
218219
currentConfiguration,
219220
imp,
220221
possibleInners,
@@ -245,9 +246,15 @@ class ModuleConcatenationPlugin {
245246
for (const concatConfiguration of concatConfigurations) {
246247
if (usedModules.has(concatConfiguration.rootModule)) continue;
247248
const modules = concatConfiguration.getModules();
249+
const rootModule = concatConfiguration.rootModule;
248250
const newModule = new ConcatenatedModule(
249-
concatConfiguration.rootModule,
250-
modules
251+
rootModule,
252+
Array.from(modules),
253+
ConcatenatedModule.createConcatenationList(
254+
rootModule,
255+
modules,
256+
compilation
257+
)
251258
);
252259
for (const warning of concatConfiguration.getWarningsSorted()) {
253260
newModule.optimizationBailout.push(requestShortener => {
@@ -320,15 +327,16 @@ class ModuleConcatenationPlugin {
320327
);
321328
}
322329

323-
getImports(module) {
330+
_getImports(compilation, module) {
324331
return new Set(
325332
module.dependencies
326333

327334
// Get reference info only for harmony Dependencies
328-
.map(
329-
dep =>
330-
dep instanceof HarmonyImportDependency ? dep.getReference() : null
331-
)
335+
.map(dep => {
336+
if (!(dep instanceof HarmonyImportDependency)) return null;
337+
if (!compilation) return dep.getReference();
338+
return compilation.getDependencyReference(module, dep);
339+
})
332340

333341
// Reference is valid and has a module
334342
// Dependencies are simple enough to concat them
@@ -345,7 +353,7 @@ class ModuleConcatenationPlugin {
345353
);
346354
}
347355

348-
tryToAdd(config, module, possibleModules, failureCache) {
356+
_tryToAdd(compilation, config, module, possibleModules, failureCache) {
349357
const cacheEntry = failureCache.get(module);
350358
if (cacheEntry) {
351359
return cacheEntry;
@@ -383,7 +391,8 @@ class ModuleConcatenationPlugin {
383391
)
384392
continue;
385393

386-
const problem = this.tryToAdd(
394+
const problem = this._tryToAdd(
395+
compilation,
387396
testConfig,
388397
reason.module,
389398
possibleModules,
@@ -399,8 +408,14 @@ class ModuleConcatenationPlugin {
399408
config.set(testConfig);
400409

401410
// Eagerly try to add imports too if possible
402-
for (const imp of this.getImports(module)) {
403-
const problem = this.tryToAdd(config, imp, possibleModules, failureCache);
411+
for (const imp of this._getImports(compilation, module)) {
412+
const problem = this._tryToAdd(
413+
compilation,
414+
config,
415+
imp,
416+
possibleModules,
417+
failureCache
418+
);
404419
if (problem) {
405420
config.addWarning(imp, problem);
406421
}
@@ -451,7 +466,7 @@ class ConcatConfiguration {
451466
}
452467

453468
getModules() {
454-
return this.modules.asArray();
469+
return this.modules.asSet();
455470
}
456471

457472
clone() {

lib/wasm/WasmFinalizeExportsPlugin.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ class WasmFinalizeExportsPlugin {
2525
for (const reason of module.reasons) {
2626
// 2. is referenced by a non-WebAssembly module
2727
if (reason.module.type.startsWith("webassembly") === false) {
28-
const ref = reason.dependency.getReference();
28+
const ref = compilation.getDependencyReference(
29+
reason.module,
30+
reason.dependency
31+
);
2932

3033
const importedNames = ref.importedNames;
3134

lib/webpack.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ exportPlugins(exports, {
123123
UmdMainTemplatePlugin: () => require("./UmdMainTemplatePlugin"),
124124
WatchIgnorePlugin: () => require("./WatchIgnorePlugin")
125125
});
126+
exportPlugins((exports.dependencies = {}), {
127+
DependencyReference: () => require("./dependencies/DependencyReference")
128+
});
126129
exportPlugins((exports.optimize = {}), {
127130
AggressiveMergingPlugin: () => require("./optimize/AggressiveMergingPlugin"),
128131
AggressiveSplittingPlugin: () =>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from "./module";
2+
3+
it("should run the test", () => {
4+
expect(test()).toEqual({
5+
used: "used",
6+
unused: undefined
7+
})
8+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { used, unused } from "./reference";
2+
3+
export function test() {
4+
return {
5+
used,
6+
unused
7+
};
8+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export var used = "used";
2+
3+
export var unused = "unused";

0 commit comments

Comments
 (0)