aboutsummaryrefslogtreecommitdiff
path: root/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js')
-rw-r--r--node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js168
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;