| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 03:12:59 +08:00
										 |  |  | const glob2regexp = require("glob-to-regexp"); | 
					
						
							| 
									
										
										
										
											2018-07-31 04:30:27 +08:00
										 |  |  | const { STAGE_DEFAULT } = require("../OptimizationStages"); | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency"); | 
					
						
							|  |  |  | const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-20 22:24:35 +08:00
										 |  |  | /** @typedef {import("../Compiler")} Compiler */ | 
					
						
							| 
									
										
										
										
											2018-05-27 05:07:02 +08:00
										 |  |  | /** @typedef {import("../Dependency")} Dependency */ | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | /** @typedef {import("../Module")} Module */ | 
					
						
							| 
									
										
										
										
											2018-05-27 05:07:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} ExportInModule | 
					
						
							|  |  |  |  * @property {Module} module the module | 
					
						
							|  |  |  |  * @property {string} exportName the name of the export | 
					
						
							| 
									
										
										
										
											2020-05-19 06:25:41 +08:00
										 |  |  |  * @property {boolean} checked if the export is conditional | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} ReexportInfo | 
					
						
							|  |  |  |  * @property {Map<string, ExportInModule[]>} static | 
					
						
							|  |  |  |  * @property {Map<Module, Set<string>>} dynamic | 
					
						
							| 
									
										
										
										
											2018-05-27 05:07:02 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 03:12:59 +08:00
										 |  |  | /** @type {WeakMap<any, Map<string, RegExp>>} */ | 
					
						
							|  |  |  | const globToRegexpCache = new WeakMap(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {string} glob the pattern | 
					
						
							|  |  |  |  * @param {Map<string, RegExp>} cache the glob to RegExp cache | 
					
						
							|  |  |  |  * @returns {RegExp} a regular expression | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const globToRegexp = (glob, cache) => { | 
					
						
							|  |  |  | 	const cacheEntry = cache.get(glob); | 
					
						
							|  |  |  | 	if (cacheEntry !== undefined) return cacheEntry; | 
					
						
							|  |  |  | 	if (!glob.includes("/")) { | 
					
						
							|  |  |  | 		glob = `**/${glob}`; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	const baseRegexp = glob2regexp(glob, { globstar: true, extended: true }); | 
					
						
							|  |  |  | 	const regexpSource = baseRegexp.source; | 
					
						
							|  |  |  | 	const regexp = new RegExp("^(\\./)?" + regexpSource.slice(1)); | 
					
						
							|  |  |  | 	cache.set(glob, regexp); | 
					
						
							|  |  |  | 	return regexp; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 19:35:25 +08:00
										 |  |  | class SideEffectsFlagPlugin { | 
					
						
							| 
									
										
										
										
											2018-07-20 22:24:35 +08:00
										 |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2020-04-23 16:48:36 +08:00
										 |  |  | 	 * Apply the plugin | 
					
						
							|  |  |  | 	 * @param {Compiler} compiler the compiler instance | 
					
						
							| 
									
										
										
										
											2018-07-20 22:24:35 +08:00
										 |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 	apply(compiler) { | 
					
						
							| 
									
										
										
										
											2019-05-17 03:12:59 +08:00
										 |  |  | 		let cache = globToRegexpCache.get(compiler.root); | 
					
						
							|  |  |  | 		if (cache === undefined) { | 
					
						
							|  |  |  | 			cache = new Map(); | 
					
						
							|  |  |  | 			globToRegexpCache.set(compiler.root, cache); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		compiler.hooks.normalModuleFactory.tap("SideEffectsFlagPlugin", nmf => { | 
					
						
							| 
									
										
										
										
											2017-12-14 04:35:39 +08:00
										 |  |  | 			nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => { | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 				const resolveData = data.resourceResolveData; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if ( | 
					
						
							|  |  |  | 					resolveData && | 
					
						
							|  |  |  | 					resolveData.descriptionFileData && | 
					
						
							|  |  |  | 					resolveData.relativePath | 
					
						
							|  |  |  | 				) { | 
					
						
							| 
									
										
										
										
											2017-10-12 23:32:41 +08:00
										 |  |  | 					const sideEffects = resolveData.descriptionFileData.sideEffects; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					const hasSideEffects = SideEffectsFlagPlugin.moduleHasSideEffects( | 
					
						
							|  |  |  | 						resolveData.relativePath, | 
					
						
							| 
									
										
										
										
											2019-05-17 03:12:59 +08:00
										 |  |  | 						sideEffects, | 
					
						
							|  |  |  | 						cache | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					); | 
					
						
							|  |  |  | 					if (!hasSideEffects) { | 
					
						
							| 
									
										
										
										
											2019-11-08 19:52:32 +08:00
										 |  |  | 						if (module.factoryMeta === undefined) { | 
					
						
							|  |  |  | 							module.factoryMeta = {}; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-12-06 19:09:17 +08:00
										 |  |  | 						module.factoryMeta.sideEffectFree = true; | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return module; | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-12-06 19:09:34 +08:00
										 |  |  | 			nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				if (data.settings.sideEffects === false) { | 
					
						
							| 
									
										
										
										
											2019-11-08 19:52:32 +08:00
										 |  |  | 					if (module.factoryMeta === undefined) { | 
					
						
							|  |  |  | 						module.factoryMeta = {}; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-12-06 19:09:34 +08:00
										 |  |  | 					module.factoryMeta.sideEffectFree = true; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} else if (data.settings.sideEffects === true) { | 
					
						
							| 
									
										
										
										
											2019-11-08 19:52:32 +08:00
										 |  |  | 					if (module.factoryMeta !== undefined) { | 
					
						
							|  |  |  | 						module.factoryMeta.sideEffectFree = false; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-01-05 02:17:37 +08:00
										 |  |  | 				return module; | 
					
						
							| 
									
										
										
										
											2017-12-06 19:09:34 +08:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		compiler.hooks.compilation.tap("SideEffectsFlagPlugin", compilation => { | 
					
						
							| 
									
										
										
										
											2018-07-24 23:35:36 +08:00
										 |  |  | 			const moduleGraph = compilation.moduleGraph; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			compilation.hooks.optimizeDependencies.tap( | 
					
						
							| 
									
										
										
										
											2018-12-09 19:54:17 +08:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2018-07-31 04:30:27 +08:00
										 |  |  | 					name: "SideEffectsFlagPlugin", | 
					
						
							|  |  |  | 					stage: STAGE_DEFAULT | 
					
						
							| 
									
										
										
										
											2018-12-09 19:54:17 +08:00
										 |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				modules => { | 
					
						
							| 
									
										
										
										
											2020-01-30 18:34:33 +08:00
										 |  |  | 					const logger = compilation.getLogger("webpack.SideEffectsFlagPlugin"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-13 05:20:45 +08:00
										 |  |  | 					logger.time("update dependencies"); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					for (const module of modules) { | 
					
						
							| 
									
										
										
										
											2020-01-30 18:59:34 +08:00
										 |  |  | 						if ( | 
					
						
							|  |  |  | 							module.factoryMeta !== undefined && | 
					
						
							|  |  |  | 							module.factoryMeta.sideEffectFree | 
					
						
							|  |  |  | 						) { | 
					
						
							| 
									
										
										
										
											2020-08-13 05:20:45 +08:00
										 |  |  | 							const exportsInfo = moduleGraph.getExportsInfo(module); | 
					
						
							|  |  |  | 							for (const connection of moduleGraph.getIncomingConnections( | 
					
						
							|  |  |  | 								module | 
					
						
							|  |  |  | 							)) { | 
					
						
							|  |  |  | 								const dep = connection.dependency; | 
					
						
							|  |  |  | 								if ( | 
					
						
							|  |  |  | 									dep instanceof HarmonyExportImportedSpecifierDependency || | 
					
						
							|  |  |  | 									(dep instanceof HarmonyImportSpecifierDependency && | 
					
						
							|  |  |  | 										!dep.namespaceObjectAsContext) | 
					
						
							|  |  |  | 								) { | 
					
						
							|  |  |  | 									// TODO improve for nested imports
 | 
					
						
							|  |  |  | 									const ids = dep.getIds(moduleGraph); | 
					
						
							|  |  |  | 									if (ids.length > 0) { | 
					
						
							|  |  |  | 										const exportInfo = exportsInfo.getExportInfo(ids[0]); | 
					
						
							|  |  |  | 										const target = exportInfo.getTarget( | 
					
						
							|  |  |  | 											moduleGraph, | 
					
						
							|  |  |  | 											({ module }) => | 
					
						
							|  |  |  | 												module.factoryMeta !== undefined && | 
					
						
							|  |  |  | 												module.factoryMeta.sideEffectFree | 
					
						
							|  |  |  | 										); | 
					
						
							|  |  |  | 										if (!target) continue; | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-13 05:20:45 +08:00
										 |  |  | 										moduleGraph.updateModule(dep, target.module); | 
					
						
							| 
									
										
										
										
											2019-03-14 19:06:59 +08:00
										 |  |  | 										moduleGraph.addExplanation( | 
					
						
							|  |  |  | 											dep, | 
					
						
							|  |  |  | 											"(skipped side-effect-free modules)" | 
					
						
							|  |  |  | 										); | 
					
						
							|  |  |  | 										dep.setIds( | 
					
						
							|  |  |  | 											moduleGraph, | 
					
						
							| 
									
										
										
										
											2020-08-13 05:20:45 +08:00
										 |  |  | 											target.export | 
					
						
							|  |  |  | 												? [...target.export, ...ids.slice(1)] | 
					
						
							| 
									
										
										
										
											2019-03-14 19:06:59 +08:00
										 |  |  | 												: ids.slice(1) | 
					
						
							|  |  |  | 										); | 
					
						
							|  |  |  | 									} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								} | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2020-08-13 05:20:45 +08:00
										 |  |  | 					logger.timeEnd("update dependencies"); | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			); | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-19 00:14:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 03:12:59 +08:00
										 |  |  | 	static moduleHasSideEffects(moduleName, flagValue, cache) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		switch (typeof flagValue) { | 
					
						
							| 
									
										
										
										
											2018-01-19 00:14:19 +08:00
										 |  |  | 			case "undefined": | 
					
						
							|  |  |  | 				return true; | 
					
						
							|  |  |  | 			case "boolean": | 
					
						
							|  |  |  | 				return flagValue; | 
					
						
							|  |  |  | 			case "string": | 
					
						
							| 
									
										
										
										
											2019-05-17 03:12:59 +08:00
										 |  |  | 				return globToRegexp(flagValue, cache).test(moduleName); | 
					
						
							| 
									
										
										
										
											2018-01-19 00:14:19 +08:00
										 |  |  | 			case "object": | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				return flagValue.some(glob => | 
					
						
							| 
									
										
										
										
											2019-05-17 03:12:59 +08:00
										 |  |  | 					SideEffectsFlagPlugin.moduleHasSideEffects(moduleName, glob, cache) | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				); | 
					
						
							| 
									
										
										
										
											2018-01-19 00:14:19 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-09-14 19:35:25 +08:00
										 |  |  | module.exports = SideEffectsFlagPlugin; |