add Compilation.getDependencyReference and hooks to override it
expose DependencyReference class
This commit is contained in:
parent
e1f0a66fd9
commit
50fe2e79ee
|
@ -36,6 +36,10 @@ const Queue = require("./util/Queue");
|
|||
const SortableSet = require("./util/SortableSet");
|
||||
const GraphHelpers = require("./GraphHelpers");
|
||||
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./dependencies/DependencyReference")} DependencyReference */
|
||||
/** @typedef {import("./Dependency")} Dependency */
|
||||
|
||||
const byId = (a, b) => {
|
||||
if (a.id < b.id) return -1;
|
||||
if (a.id > b.id) return 1;
|
||||
|
@ -104,6 +108,13 @@ class Compilation extends Tapable {
|
|||
failedModule: new SyncHook(["module", "error"]),
|
||||
succeedModule: new SyncHook(["module"]),
|
||||
|
||||
/** @type {SyncWaterfallHook<DependencyReference, Dependency, Module>} */
|
||||
dependencyReference: new SyncWaterfallHook([
|
||||
"dependencyReference",
|
||||
"dependency",
|
||||
"module"
|
||||
]),
|
||||
|
||||
finishModules: new SyncHook(["modules"]),
|
||||
finishRebuildingModule: new SyncHook(["module"]),
|
||||
|
||||
|
@ -1175,6 +1186,19 @@ class Compilation extends Tapable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the module containing the dependency
|
||||
* @param {Dependency} dependency the dependency
|
||||
* @returns {DependencyReference} a reference for the dependency
|
||||
*/
|
||||
getDependencyReference(module, dependency) {
|
||||
// TODO remove dep.getReference existance check in webpack 5
|
||||
if (typeof dependency.getReference !== "function") return null;
|
||||
const ref = dependency.getReference();
|
||||
if (!ref) return null;
|
||||
return this.hooks.dependencyReference.call(ref, dependency, module);
|
||||
}
|
||||
|
||||
// This method creates the Chunk graph from the Module graph
|
||||
processDependenciesBlocksForChunkGroups(inputChunkGroups) {
|
||||
// Process is splitting into two parts:
|
||||
|
@ -1193,7 +1217,7 @@ class Compilation extends Tapable {
|
|||
|
||||
const iteratorDependency = d => {
|
||||
// We skip Dependencies without Reference
|
||||
const ref = d.getReference();
|
||||
const ref = this.getDependencyReference(currentModule, d);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
|
@ -1215,9 +1239,12 @@ class Compilation extends Tapable {
|
|||
blockQueue.push(b);
|
||||
};
|
||||
|
||||
/** @type {Module} */
|
||||
let currentModule;
|
||||
let block, blockQueue, blockInfoModules, blockInfoBlocks;
|
||||
for (const module of this.modules) {
|
||||
blockQueue = [module];
|
||||
currentModule = module;
|
||||
while (blockQueue.length > 0) {
|
||||
block = blockQueue.pop();
|
||||
blockInfoModules = new Set();
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
*/
|
||||
"use strict";
|
||||
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
|
||||
|
||||
/** @typedef {false | true | string[]} UsedExports */
|
||||
|
||||
const addToSet = (a, b) => {
|
||||
for (const item of b) {
|
||||
if (!a.includes(item)) a.push(item);
|
||||
|
@ -54,37 +59,36 @@ class FlagDependencyUsagePlugin {
|
|||
return;
|
||||
}
|
||||
|
||||
queue.push([module, module.usedExports]);
|
||||
queue.push([module, module, module.usedExports]);
|
||||
};
|
||||
|
||||
const processDependenciesBlock = (depBlock, usedExports) => {
|
||||
const processDependenciesBlock = (module, depBlock, usedExports) => {
|
||||
for (const dep of depBlock.dependencies) {
|
||||
processDependency(dep);
|
||||
processDependency(module, dep);
|
||||
}
|
||||
for (const variable of depBlock.variables) {
|
||||
for (const dep of variable.dependencies) {
|
||||
processDependency(dep);
|
||||
processDependency(module, dep);
|
||||
}
|
||||
}
|
||||
for (const block of depBlock.blocks) {
|
||||
queue.push([block, usedExports]);
|
||||
queue.push([module, block, usedExports]);
|
||||
}
|
||||
};
|
||||
|
||||
const processDependency = dep => {
|
||||
// TODO remove dep.getReference existance check in webpack 5
|
||||
const reference = dep.getReference && dep.getReference();
|
||||
const processDependency = (module, dep) => {
|
||||
const reference = compilation.getDependencyReference(module, dep);
|
||||
if (!reference) return;
|
||||
const module = reference.module;
|
||||
const referenceModule = reference.module;
|
||||
const importedNames = reference.importedNames;
|
||||
const oldUsed = module.used;
|
||||
const oldUsedExports = module.usedExports;
|
||||
const oldUsed = referenceModule.used;
|
||||
const oldUsedExports = referenceModule.usedExports;
|
||||
if (
|
||||
!oldUsed ||
|
||||
(importedNames &&
|
||||
(!oldUsedExports || !isSubset(oldUsedExports, importedNames)))
|
||||
) {
|
||||
processModule(module, importedNames);
|
||||
processModule(referenceModule, importedNames);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -92,6 +96,7 @@ class FlagDependencyUsagePlugin {
|
|||
module.used = false;
|
||||
}
|
||||
|
||||
/** @type {[Module, DependenciesBlock, UsedExports][]} */
|
||||
const queue = [];
|
||||
for (const preparedEntrypoint of compilation._preparedEntrypoints) {
|
||||
if (preparedEntrypoint.module) {
|
||||
|
@ -101,7 +106,7 @@ class FlagDependencyUsagePlugin {
|
|||
|
||||
while (queue.length) {
|
||||
const queueItem = queue.pop();
|
||||
processDependenciesBlock(queueItem[0], queueItem[1]);
|
||||
processDependenciesBlock(queueItem[0], queueItem[1], queueItem[2]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -265,6 +265,10 @@ module.exports = class RuntimeTemplate {
|
|||
|
||||
if (exportName) {
|
||||
const used = module.isUsed(exportName);
|
||||
if (!used) {
|
||||
const comment = Template.toNormalComment(`unused export ${exportName}`);
|
||||
return `${comment} undefined`;
|
||||
}
|
||||
const comment =
|
||||
used !== exportName ? Template.toNormalComment(exportName) + " " : "";
|
||||
const access = `${importVar}[${comment}${JSON.stringify(used)}]`;
|
||||
|
|
|
@ -20,6 +20,13 @@ const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibi
|
|||
const createHash = require("../util/createHash");
|
||||
|
||||
/** @typedef {import("../Dependency")} Dependency */
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
|
||||
/**
|
||||
* @typedef {Object} ConcatenationEntry
|
||||
* @property {"concatenated" | "external"} type
|
||||
* @property {Module} module
|
||||
*/
|
||||
|
||||
const ensureNsObjSource = (
|
||||
info,
|
||||
|
@ -275,7 +282,7 @@ const getPathInAst = (ast, node) => {
|
|||
};
|
||||
|
||||
class ConcatenatedModule extends Module {
|
||||
constructor(rootModule, modules) {
|
||||
constructor(rootModule, modules, concatenationList) {
|
||||
super("javascript/esm", null);
|
||||
super.setChunks(rootModule._chunks);
|
||||
|
||||
|
@ -319,10 +326,9 @@ class ConcatenatedModule extends Module {
|
|||
|
||||
this.warnings = [];
|
||||
this.errors = [];
|
||||
this._orderedConcatenationList = this._createOrderedConcatenationList(
|
||||
rootModule,
|
||||
modulesSet
|
||||
);
|
||||
this._orderedConcatenationList =
|
||||
concatenationList ||
|
||||
ConcatenatedModule.createConcatenationList(rootModule, modulesSet, null);
|
||||
for (const info of this._orderedConcatenationList) {
|
||||
if (info.type === "concatenated") {
|
||||
const m = info.module;
|
||||
|
@ -409,7 +415,13 @@ class ConcatenatedModule extends Module {
|
|||
}, 0);
|
||||
}
|
||||
|
||||
_createOrderedConcatenationList(rootModule, modulesSet) {
|
||||
/**
|
||||
* @param {Module} rootModule the root of the concatenation
|
||||
* @param {Set<Module>} modulesSet a set of modules which should be concatenated
|
||||
* @param {Compilation} compilation the compilation context
|
||||
* @returns {ConcatenationEntry[]} concatenation list
|
||||
*/
|
||||
static createConcatenationList(rootModule, modulesSet, compilation) {
|
||||
const list = [];
|
||||
const set = new Set();
|
||||
|
||||
|
@ -423,7 +435,7 @@ class ConcatenatedModule extends Module {
|
|||
const references = module.dependencies
|
||||
.filter(dep => dep instanceof HarmonyImportDependency)
|
||||
.map(dep => {
|
||||
const ref = dep.getReference();
|
||||
const ref = compilation.getDependencyReference(module, dep);
|
||||
if (ref) map.set(ref, dep);
|
||||
return ref;
|
||||
})
|
||||
|
@ -432,7 +444,7 @@ class ConcatenatedModule extends Module {
|
|||
// TODO webpack 5: remove this hack, see also DependencyReference
|
||||
return references.map(ref => {
|
||||
const dep = map.get(ref);
|
||||
return () => dep.getReference().module;
|
||||
return () => compilation.getDependencyReference(module, dep).module;
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -213,8 +213,9 @@ class ModuleConcatenationPlugin {
|
|||
const failureCache = new Map();
|
||||
|
||||
// try to add all imports
|
||||
for (const imp of this.getImports(currentRoot)) {
|
||||
const problem = this.tryToAdd(
|
||||
for (const imp of this._getImports(compilation, currentRoot)) {
|
||||
const problem = this._tryToAdd(
|
||||
compilation,
|
||||
currentConfiguration,
|
||||
imp,
|
||||
possibleInners,
|
||||
|
@ -245,9 +246,15 @@ class ModuleConcatenationPlugin {
|
|||
for (const concatConfiguration of concatConfigurations) {
|
||||
if (usedModules.has(concatConfiguration.rootModule)) continue;
|
||||
const modules = concatConfiguration.getModules();
|
||||
const rootModule = concatConfiguration.rootModule;
|
||||
const newModule = new ConcatenatedModule(
|
||||
concatConfiguration.rootModule,
|
||||
modules
|
||||
rootModule,
|
||||
Array.from(modules),
|
||||
ConcatenatedModule.createConcatenationList(
|
||||
rootModule,
|
||||
modules,
|
||||
compilation
|
||||
)
|
||||
);
|
||||
for (const warning of concatConfiguration.getWarningsSorted()) {
|
||||
newModule.optimizationBailout.push(requestShortener => {
|
||||
|
@ -320,15 +327,16 @@ class ModuleConcatenationPlugin {
|
|||
);
|
||||
}
|
||||
|
||||
getImports(module) {
|
||||
_getImports(compilation, module) {
|
||||
return new Set(
|
||||
module.dependencies
|
||||
|
||||
// Get reference info only for harmony Dependencies
|
||||
.map(
|
||||
dep =>
|
||||
dep instanceof HarmonyImportDependency ? dep.getReference() : null
|
||||
)
|
||||
.map(dep => {
|
||||
if (!(dep instanceof HarmonyImportDependency)) return null;
|
||||
if (!compilation) return dep.getReference();
|
||||
return compilation.getDependencyReference(module, dep);
|
||||
})
|
||||
|
||||
// Reference is valid and has a module
|
||||
// Dependencies are simple enough to concat them
|
||||
|
@ -345,7 +353,7 @@ class ModuleConcatenationPlugin {
|
|||
);
|
||||
}
|
||||
|
||||
tryToAdd(config, module, possibleModules, failureCache) {
|
||||
_tryToAdd(compilation, config, module, possibleModules, failureCache) {
|
||||
const cacheEntry = failureCache.get(module);
|
||||
if (cacheEntry) {
|
||||
return cacheEntry;
|
||||
|
@ -383,7 +391,8 @@ class ModuleConcatenationPlugin {
|
|||
)
|
||||
continue;
|
||||
|
||||
const problem = this.tryToAdd(
|
||||
const problem = this._tryToAdd(
|
||||
compilation,
|
||||
testConfig,
|
||||
reason.module,
|
||||
possibleModules,
|
||||
|
@ -399,8 +408,14 @@ class ModuleConcatenationPlugin {
|
|||
config.set(testConfig);
|
||||
|
||||
// Eagerly try to add imports too if possible
|
||||
for (const imp of this.getImports(module)) {
|
||||
const problem = this.tryToAdd(config, imp, possibleModules, failureCache);
|
||||
for (const imp of this._getImports(compilation, module)) {
|
||||
const problem = this._tryToAdd(
|
||||
compilation,
|
||||
config,
|
||||
imp,
|
||||
possibleModules,
|
||||
failureCache
|
||||
);
|
||||
if (problem) {
|
||||
config.addWarning(imp, problem);
|
||||
}
|
||||
|
@ -451,7 +466,7 @@ class ConcatConfiguration {
|
|||
}
|
||||
|
||||
getModules() {
|
||||
return this.modules.asArray();
|
||||
return this.modules.asSet();
|
||||
}
|
||||
|
||||
clone() {
|
||||
|
|
|
@ -25,7 +25,10 @@ class WasmFinalizeExportsPlugin {
|
|||
for (const reason of module.reasons) {
|
||||
// 2. is referenced by a non-WebAssembly module
|
||||
if (reason.module.type.startsWith("webassembly") === false) {
|
||||
const ref = reason.dependency.getReference();
|
||||
const ref = compilation.getDependencyReference(
|
||||
reason.module,
|
||||
reason.dependency
|
||||
);
|
||||
|
||||
const importedNames = ref.importedNames;
|
||||
|
||||
|
|
|
@ -123,6 +123,9 @@ exportPlugins(exports, {
|
|||
UmdMainTemplatePlugin: () => require("./UmdMainTemplatePlugin"),
|
||||
WatchIgnorePlugin: () => require("./WatchIgnorePlugin")
|
||||
});
|
||||
exportPlugins((exports.dependencies = {}), {
|
||||
DependencyReference: () => require("./dependencies/DependencyReference")
|
||||
});
|
||||
exportPlugins((exports.optimize = {}), {
|
||||
AggressiveMergingPlugin: () => require("./optimize/AggressiveMergingPlugin"),
|
||||
AggressiveSplittingPlugin: () =>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import { test } from "./module";
|
||||
|
||||
it("should run the test", () => {
|
||||
expect(test()).toEqual({
|
||||
used: "used",
|
||||
unused: undefined
|
||||
})
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
import { used, unused } from "./reference";
|
||||
|
||||
export function test() {
|
||||
return {
|
||||
used,
|
||||
unused
|
||||
};
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export var used = "used";
|
||||
|
||||
export var unused = "unused";
|
|
@ -0,0 +1,34 @@
|
|||
const DependencyReference = require("../../../../").dependencies
|
||||
.DependencyReference;
|
||||
module.exports = {
|
||||
optimization: {
|
||||
usedExports: true,
|
||||
concatenateModules: false
|
||||
},
|
||||
plugins: [
|
||||
function() {
|
||||
this.hooks.compilation.tap("Test", compilation => {
|
||||
compilation.hooks.dependencyReference.tap(
|
||||
"Test",
|
||||
(ref, dep, module) => {
|
||||
if (
|
||||
module.identifier().endsWith("module.js") &&
|
||||
ref.module &&
|
||||
ref.module.identifier().endsWith("reference.js") &&
|
||||
Array.isArray(ref.importedNames) &&
|
||||
ref.importedNames.includes("unused")
|
||||
) {
|
||||
return new DependencyReference(
|
||||
ref.module,
|
||||
ref.importedNames.filter(item => item !== "unused"),
|
||||
ref.weak,
|
||||
ref.order
|
||||
);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
]
|
||||
};
|
Loading…
Reference in New Issue