175 lines
4.9 KiB
JavaScript
175 lines
4.9 KiB
JavaScript
|
/*
|
||
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
||
|
Author Tobias Koppers @sokra
|
||
|
*/
|
||
|
"use strict";
|
||
|
|
||
|
const Queue = require("./util/Queue");
|
||
|
|
||
|
const addToSet = (a, b) => {
|
||
|
for (const item of b) {
|
||
|
a.add(item);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class FlagDependencyExportsPlugin {
|
||
|
apply(compiler) {
|
||
|
compiler.hooks.compilation.tap(
|
||
|
"FlagDependencyExportsPlugin",
|
||
|
compilation => {
|
||
|
compilation.hooks.finishModules.tap(
|
||
|
"FlagDependencyExportsPlugin",
|
||
|
modules => {
|
||
|
const dependencies = new Map();
|
||
|
|
||
|
const queue = new Queue();
|
||
|
|
||
|
let module;
|
||
|
let moduleWithExports;
|
||
|
let moduleProvidedExports;
|
||
|
let providedExportsAreTemporary;
|
||
|
|
||
|
const processDependenciesBlock = depBlock => {
|
||
|
for (const dep of depBlock.dependencies) {
|
||
|
if (processDependency(dep)) return true;
|
||
|
}
|
||
|
for (const variable of depBlock.variables) {
|
||
|
for (const dep of variable.dependencies) {
|
||
|
if (processDependency(dep)) return true;
|
||
|
}
|
||
|
}
|
||
|
for (const block of depBlock.blocks) {
|
||
|
if (processDependenciesBlock(block)) return true;
|
||
|
}
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
const processDependency = dep => {
|
||
|
const exportDesc = dep.getExports && dep.getExports();
|
||
|
if (!exportDesc) return;
|
||
|
moduleWithExports = true;
|
||
|
const exports = exportDesc.exports;
|
||
|
// break early if it's only in the worst state
|
||
|
if (module.buildMeta.providedExports === true) {
|
||
|
return true;
|
||
|
}
|
||
|
// break if it should move to the worst state
|
||
|
if (exports === true) {
|
||
|
module.buildMeta.providedExports = true;
|
||
|
return true;
|
||
|
}
|
||
|
// merge in new exports
|
||
|
if (Array.isArray(exports)) {
|
||
|
addToSet(moduleProvidedExports, exports);
|
||
|
}
|
||
|
// store dependencies
|
||
|
const exportDeps = exportDesc.dependencies;
|
||
|
if (exportDeps) {
|
||
|
providedExportsAreTemporary = true;
|
||
|
for (const exportDependency of exportDeps) {
|
||
|
// add dependency for this module
|
||
|
const set = dependencies.get(exportDependency);
|
||
|
if (set === undefined) {
|
||
|
dependencies.set(exportDependency, new Set([module]));
|
||
|
} else {
|
||
|
set.add(module);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
const notifyDependencies = () => {
|
||
|
const deps = dependencies.get(module);
|
||
|
if (deps !== undefined) {
|
||
|
for (const dep of deps) {
|
||
|
queue.enqueue(dep);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const notifyDependenciesIfDifferent = (set, array) => {
|
||
|
const deps = dependencies.get(module);
|
||
|
if (deps !== undefined) {
|
||
|
if (set.size === array.length) {
|
||
|
let i = 0;
|
||
|
let different = false;
|
||
|
for (const item of set) {
|
||
|
if (item !== array[i++]) {
|
||
|
different = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!different) return;
|
||
|
}
|
||
|
for (const dep of deps) {
|
||
|
queue.enqueue(dep);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Start with all modules without provided exports
|
||
|
for (const module of modules) {
|
||
|
if (module.buildInfo.temporaryProvidedExports) {
|
||
|
// Clear exports when they are temporary
|
||
|
// and recreate them
|
||
|
module.buildMeta.providedExports = null;
|
||
|
queue.enqueue(module);
|
||
|
} else if (!module.buildMeta.providedExports) {
|
||
|
queue.enqueue(module);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (queue.length > 0) {
|
||
|
module = queue.dequeue();
|
||
|
|
||
|
if (module.buildMeta.providedExports !== true) {
|
||
|
moduleWithExports =
|
||
|
module.buildMeta && module.buildMeta.exportsType;
|
||
|
moduleProvidedExports = new Set();
|
||
|
providedExportsAreTemporary = false;
|
||
|
processDependenciesBlock(module);
|
||
|
module.buildInfo.temporaryProvidedExports = providedExportsAreTemporary;
|
||
|
if (!moduleWithExports) {
|
||
|
notifyDependencies();
|
||
|
module.buildMeta.providedExports = true;
|
||
|
} else if (module.buildMeta.providedExports === true) {
|
||
|
notifyDependencies();
|
||
|
} else if (!module.buildMeta.providedExports) {
|
||
|
notifyDependencies();
|
||
|
module.buildMeta.providedExports = Array.from(
|
||
|
moduleProvidedExports
|
||
|
);
|
||
|
} else {
|
||
|
notifyDependenciesIfDifferent(
|
||
|
moduleProvidedExports,
|
||
|
module.buildMeta.providedExports
|
||
|
);
|
||
|
module.buildMeta.providedExports = Array.from(
|
||
|
moduleProvidedExports
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
const providedExportsCache = new WeakMap();
|
||
|
compilation.hooks.rebuildModule.tap(
|
||
|
"FlagDependencyExportsPlugin",
|
||
|
module => {
|
||
|
providedExportsCache.set(module, module.buildMeta.providedExports);
|
||
|
}
|
||
|
);
|
||
|
compilation.hooks.finishRebuildingModule.tap(
|
||
|
"FlagDependencyExportsPlugin",
|
||
|
module => {
|
||
|
module.buildMeta.providedExports = providedExportsCache.get(module);
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = FlagDependencyExportsPlugin;
|