webpack/lib/FlagDependencyExportsPlugin.js

190 lines
5.2 KiB
JavaScript
Raw Normal View History

/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
2018-07-30 23:08:51 +08:00
"use strict";
const Queue = require("./util/Queue");
2018-07-28 03:12:09 +08:00
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
/** @typedef {import("./Dependency")} Dependency */
/** @typedef {import("./Module")} Module */
2018-07-28 03:12:09 +08:00
2017-11-08 18:32:05 +08:00
const addToSet = (a, b) => {
let changed = false;
2018-02-25 09:00:20 +08:00
for (const item of b) {
if (!a.has(item)) {
2017-11-08 18:32:05 +08:00
a.add(item);
changed = true;
}
}
2017-11-08 18:32:05 +08:00
return changed;
};
class FlagDependencyExportsPlugin {
2018-07-28 03:12:09 +08:00
/**
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
2018-02-25 09:00:20 +08:00
compiler.hooks.compilation.tap(
"FlagDependencyExportsPlugin",
compilation => {
const moduleGraph = compilation.moduleGraph;
2018-02-25 09:00:20 +08:00
compilation.hooks.finishModules.tap(
"FlagDependencyExportsPlugin",
modules => {
/** @type {Map<Module, Set<Module>>} */
2018-02-25 09:00:20 +08:00
const dependencies = new Map();
/** @type {Queue<Module>} */
2018-02-25 09:00:20 +08:00
const queue = new Queue();
/** @type {WeakSet<Module>} */
const temporaryProvidedExports = new WeakSet();
2017-11-08 18:32:05 +08:00
2018-02-25 09:00:20 +08:00
let module;
let moduleWithExports;
let moduleProvidedExports;
let providedExportsAreTemporary = false;
/**
* @param {DependenciesBlock} depBlock the dependencies block
* @returns {boolean} true if the traversal must be continued
*/
2018-02-25 09:00:20 +08:00
const processDependenciesBlock = depBlock => {
for (const dep of depBlock.dependencies) {
if (processDependency(dep)) {
return true;
}
2018-02-25 09:00:20 +08:00
}
for (const block of depBlock.blocks) {
if (processDependenciesBlock(block)) {
return true;
}
2018-02-25 09:00:20 +08:00
}
return false;
};
/**
* @param {Dependency} dep the dependency
* @returns {boolean} true if the traversal must be continued
*/
2018-02-25 09:00:20 +08:00
const processDependency = dep => {
const exportDesc = dep.getExports(moduleGraph);
2018-02-25 09:00:20 +08:00
if (!exportDesc) return;
moduleWithExports = true;
const exports = exportDesc.exports;
// break early if it's only in the worst state
if (moduleGraph.getProvidedExports(module) === true) {
return true;
2018-02-25 09:00:20 +08:00
}
// break if it should move to the worst state
if (exports === true) {
moduleGraph.setProvidedExports(module, true);
2018-02-25 09:00:20 +08:00
notifyDependencies();
return true;
}
// merge in new exports
if (Array.isArray(exports)) {
if (addToSet(moduleProvidedExports, exports)) {
notifyDependencies();
}
}
// store dependencies
const exportDeps = exportDesc.dependencies;
if (exportDeps) {
providedExportsAreTemporary = true;
2018-02-25 09:00:20 +08:00
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;
};
2018-02-25 09:00:20 +08:00
const notifyDependencies = () => {
const deps = dependencies.get(module);
if (deps !== undefined) {
for (const dep of deps) {
queue.enqueue(dep);
}
}
2018-02-25 09:00:20 +08:00
};
2016-09-09 20:50:14 +08:00
2018-02-25 09:00:20 +08:00
// Start with all modules without provided exports
for (const module of modules) {
if (temporaryProvidedExports.has(module)) {
// Clear exports when they are temporary and recreate them
moduleGraph.setProvidedExports(module, null);
queue.enqueue(module);
} else if (!moduleGraph.getProvidedExports(module)) {
2018-02-25 09:00:20 +08:00
queue.enqueue(module);
}
}
2018-02-25 09:00:20 +08:00
while (queue.length > 0) {
module = queue.dequeue();
const providedExports = moduleGraph.getProvidedExports(module);
if (providedExports !== true) {
2018-02-25 09:00:20 +08:00
moduleWithExports =
module.buildMeta && module.buildMeta.exportsType;
moduleProvidedExports = Array.isArray(providedExports)
? new Set(providedExports)
2018-02-25 09:00:20 +08:00
: new Set();
providedExportsAreTemporary = false;
2018-02-25 09:00:20 +08:00
processDependenciesBlock(module);
if (providedExportsAreTemporary) {
temporaryProvidedExports.add(module);
} else {
temporaryProvidedExports.delete(module);
}
2018-02-25 09:00:20 +08:00
if (!moduleWithExports) {
moduleGraph.setProvidedExports(module, true);
2018-02-25 09:00:20 +08:00
notifyDependencies();
} else if (moduleGraph.getProvidedExports(module) !== true) {
moduleGraph.setProvidedExports(
module,
Array.from(moduleProvidedExports)
2018-02-25 09:00:20 +08:00
);
}
}
2017-11-08 18:32:05 +08:00
}
}
2018-02-25 09:00:20 +08:00
);
2018-02-25 09:00:20 +08:00
const providedExportsCache = new WeakMap();
compilation.hooks.rebuildModule.tap(
"FlagDependencyExportsPlugin",
module => {
providedExportsCache.set(
module,
moduleGraph.getProvidedExports(module)
);
2018-02-25 09:00:20 +08:00
}
);
compilation.hooks.finishRebuildingModule.tap(
"FlagDependencyExportsPlugin",
module => {
moduleGraph.setProvidedExports(
module,
providedExportsCache.get(module)
);
2018-02-25 09:00:20 +08:00
}
);
}
);
}
}
module.exports = FlagDependencyExportsPlugin;