/* 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) => { const size = a.size; for (const item of b) { a.add(item); } return a.size !== size; }; 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; 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; 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); } } }; // 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) { module.buildMeta.providedExports = true; notifyDependencies(); } else if (module.buildMeta.providedExports !== true) { 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;