diff options
Diffstat (limited to 'node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js')
| -rw-r--r-- | node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js b/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js new file mode 100644 index 00000000..4b618c29 --- /dev/null +++ b/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js @@ -0,0 +1,168 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const mm = require("micromatch"); +const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency"); +const HarmonyImportSideEffectDependency = require("../dependencies/HarmonyImportSideEffectDependency"); +const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency"); + +/** @typedef {import("../Module")} Module */ +/** @typedef {import("../Dependency")} Dependency */ + +/** + * @typedef {Object} ExportInModule + * @property {Module} module the module + * @property {string} exportName the name of the export + */ + +class SideEffectsFlagPlugin { + apply(compiler) { + compiler.hooks.normalModuleFactory.tap("SideEffectsFlagPlugin", nmf => { + nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => { + const resolveData = data.resourceResolveData; + if ( + resolveData && + resolveData.descriptionFileData && + resolveData.relativePath + ) { + const sideEffects = resolveData.descriptionFileData.sideEffects; + const hasSideEffects = SideEffectsFlagPlugin.moduleHasSideEffects( + resolveData.relativePath, + sideEffects + ); + if (!hasSideEffects) { + module.factoryMeta.sideEffectFree = true; + } + } + + return module; + }); + nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => { + if (data.settings.sideEffects === false) { + module.factoryMeta.sideEffectFree = true; + } else if (data.settings.sideEffects === true) { + module.factoryMeta.sideEffectFree = false; + } + }); + }); + compiler.hooks.compilation.tap("SideEffectsFlagPlugin", compilation => { + compilation.hooks.optimizeDependencies.tap( + "SideEffectsFlagPlugin", + modules => { + /** @type {Map<Module, Map<string, ExportInModule>>} */ + const reexportMaps = new Map(); + + // Capture reexports of sideEffectFree modules + for (const module of modules) { + /** @type {Dependency[]} */ + const removeDependencies = []; + for (const dep of module.dependencies) { + if (dep instanceof HarmonyImportSideEffectDependency) { + if (dep.module && dep.module.factoryMeta.sideEffectFree) { + removeDependencies.push(dep); + } + } else if ( + dep instanceof HarmonyExportImportedSpecifierDependency + ) { + if (module.factoryMeta.sideEffectFree) { + const mode = dep.getMode(true); + if (mode.type === "safe-reexport") { + let map = reexportMaps.get(module); + if (!map) { + reexportMaps.set(module, (map = new Map())); + } + for (const pair of mode.map) { + map.set(pair[0], { + module: mode.module, + exportName: pair[1] + }); + } + } + } + } + } + } + + // Flatten reexports + for (const map of reexportMaps.values()) { + for (const pair of map) { + let mapping = pair[1]; + while (mapping) { + const innerMap = reexportMaps.get(mapping.module); + if (!innerMap) break; + const newMapping = innerMap.get(mapping.exportName); + if (newMapping) { + map.set(pair[0], newMapping); + } + mapping = newMapping; + } + } + } + + // Update imports along the reexports from sideEffectFree modules + for (const pair of reexportMaps) { + const module = pair[0]; + const map = pair[1]; + let newReasons = undefined; + for (let i = 0; i < module.reasons.length; i++) { + const reason = module.reasons[i]; + const dep = reason.dependency; + if ( + dep instanceof HarmonyImportSpecifierDependency && + !dep.namespaceObjectAsContext + ) { + const mapping = map.get(dep.id); + if (mapping) { + dep.redirectedModule = mapping.module; + dep.redirectedId = mapping.exportName; + mapping.module.addReason( + reason.module, + dep, + reason.explanation + ? reason.explanation + + " (skipped side-effect-free modules)" + : "(skipped side-effect-free modules)" + ); + // removing the currect reason, by not adding it to the newReasons array + // lazily create the newReasons array + if (newReasons === undefined) { + newReasons = i === 0 ? [] : module.reasons.slice(0, i); + } + continue; + } + } + if (newReasons !== undefined) newReasons.push(reason); + } + if (newReasons !== undefined) { + module.reasons = newReasons; + } + } + } + ); + }); + } + + static moduleHasSideEffects(moduleName, flagValue) { + switch (typeof flagValue) { + case "undefined": + return true; + case "boolean": + return flagValue; + case "string": + if (process.platform === "win32") { + flagValue = flagValue.replace(/\\/g, "/"); + } + return mm.isMatch(moduleName, flagValue, { + matchBase: true + }); + case "object": + return flagValue.some(glob => + SideEffectsFlagPlugin.moduleHasSideEffects(moduleName, glob) + ); + } + } +} +module.exports = SideEffectsFlagPlugin; |
