diff --git a/lib/FlagDependencyUsagePlugin.js b/lib/FlagDependencyUsagePlugin.js index c49c609fa..d7d8b79f6 100644 --- a/lib/FlagDependencyUsagePlugin.js +++ b/lib/FlagDependencyUsagePlugin.js @@ -19,6 +19,7 @@ const { getEntryRuntime, mergeRuntimeOwned } = require("./util/runtime"); /** @typedef {import("./Dependency").ReferencedExports} ReferencedExports */ /** @typedef {import("./ExportsInfo")} ExportsInfo */ /** @typedef {import("./Module")} Module */ +/** @typedef {import("./ModuleGraph")} ModuleGraph */ /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */ const { NO_EXPORTS_REFERENCED, EXPORTS_OBJECT_REFERENCED } = Dependency; @@ -34,6 +35,48 @@ class FlagDependencyUsagePlugin { this.global = global; } + /** + * Check if a module is doing pass-through re-exports + * @param {Module} module the module to check + * @param {ModuleGraph} moduleGraph the module graph + * @returns {boolean} true if the module is doing pass-through re-exports + */ + _isPassThroughReexport(module, moduleGraph) { + if (!module.dependencies || module.dependencies.length === 0) { + return false; + } + + let hasReexportDeps = false; + let hasOtherDeps = false; + + for (const dep of module.dependencies) { + if ( + dep.type === "harmony export imported specifier" || + dep.type === "harmony export specifier" || + dep.type === "harmony reexport" || + (dep.constructor && dep.constructor.name.includes("Reexport")) + ) { + hasReexportDeps = true; + } else if ( + dep.type !== "harmony import" && + dep.type !== "harmony import specifier" + ) { + hasOtherDeps = true; + } + } + + const exportsInfo = moduleGraph.getExportsInfo(module); + let hasOwnExports = false; + for (const exportInfo of exportsInfo.ownedExports) { + if (exportInfo.provided === true && !exportInfo.exportsInfoOwned) { + hasOwnExports = true; + break; + } + } + + return hasReexportDeps && !hasOtherDeps && !hasOwnExports; + } + /** * Apply the plugin * @param {Compiler} compiler the compiler instance @@ -89,7 +132,16 @@ class FlagDependencyUsagePlugin { canMangle = usedExportInfo.canMangle !== false; } if (usedExport.length === 0) { - if (exportsInfo.setUsedInUnknownWay(runtime)) { + const isPassThroughReexport = this._isPassThroughReexport( + module, + moduleGraph + ); + + if (isPassThroughReexport) { + if (exportsInfo.setUsedForSideEffectsOnly(runtime)) { + queue.enqueue(module, runtime); + } + } else if (exportsInfo.setUsedInUnknownWay(runtime)) { queue.enqueue(module, runtime); } } else {