| 
									
										
										
										
											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"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 00:36:14 +08:00
										 |  |  | const mm = require("micromatch"); | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency"); | 
					
						
							|  |  |  | const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 19:35:25 +08:00
										 |  |  | class SideEffectsFlagPlugin { | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 	apply(compiler) { | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							|  |  |  | 						sideEffects | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					if (!hasSideEffects) { | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2017-12-06 19:09:34 +08:00
										 |  |  | 					module.factoryMeta.sideEffectFree = false; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											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 => { | 
					
						
							|  |  |  | 			compilation.hooks.optimizeDependencies.tap( | 
					
						
							|  |  |  | 				"SideEffectsFlagPlugin", | 
					
						
							|  |  |  | 				modules => { | 
					
						
							| 
									
										
										
										
											2018-05-27 05:07:02 +08:00
										 |  |  | 					/** @type {Map<Module, Map<string, ExportInModule>>} */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					const reexportMaps = new Map(); | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					// Capture reexports of sideEffectFree modules
 | 
					
						
							|  |  |  | 					for (const module of modules) { | 
					
						
							|  |  |  | 						for (const dep of module.dependencies) { | 
					
						
							| 
									
										
										
										
											2018-07-24 23:35:11 +08:00
										 |  |  | 							if (dep instanceof HarmonyExportImportedSpecifierDependency) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								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], { | 
					
						
							| 
									
										
										
										
											2018-07-17 20:04:26 +08:00
										 |  |  | 												module: mode.getModule(), | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 												exportName: pair[1] | 
					
						
							|  |  |  | 											}); | 
					
						
							|  |  |  | 										} | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 									} | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					// 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; | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					// Update imports along the reexports from sideEffectFree modules
 | 
					
						
							|  |  |  | 					for (const pair of reexportMaps) { | 
					
						
							|  |  |  | 						const module = pair[0]; | 
					
						
							|  |  |  | 						const map = pair[1]; | 
					
						
							| 
									
										
										
										
											2018-05-30 00:14:16 +08:00
										 |  |  | 						let newReasons = undefined; | 
					
						
							| 
									
										
										
										
											2018-05-29 19:45:32 +08:00
										 |  |  | 						for (let i = 0; i < module.reasons.length; i++) { | 
					
						
							|  |  |  | 							const reason = module.reasons[i]; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							const dep = reason.dependency; | 
					
						
							| 
									
										
										
										
											2018-05-28 03:47:58 +08:00
										 |  |  | 							if ( | 
					
						
							|  |  |  | 								dep instanceof HarmonyImportSpecifierDependency && | 
					
						
							|  |  |  | 								!dep.namespaceObjectAsContext | 
					
						
							|  |  |  | 							) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								const mapping = map.get(dep.id); | 
					
						
							|  |  |  | 								if (mapping) { | 
					
						
							| 
									
										
										
										
											2018-05-27 05:07:02 +08:00
										 |  |  | 									dep.redirectedModule = mapping.module; | 
					
						
							|  |  |  | 									dep.redirectedId = mapping.exportName; | 
					
						
							| 
									
										
										
										
											2018-05-29 19:45:32 +08:00
										 |  |  | 									mapping.module.addReason( | 
					
						
							|  |  |  | 										reason.module, | 
					
						
							|  |  |  | 										dep, | 
					
						
							|  |  |  | 										reason.explanation | 
					
						
							|  |  |  | 											? reason.explanation + | 
					
						
							|  |  |  | 											  " (skipped side-effect-free modules)" | 
					
						
							|  |  |  | 											: "(skipped side-effect-free modules)" | 
					
						
							|  |  |  | 									); | 
					
						
							| 
									
										
										
										
											2018-05-30 00:14:16 +08:00
										 |  |  | 									// 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; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								} | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2018-05-30 00:14:16 +08:00
										 |  |  | 							if (newReasons !== undefined) newReasons.push(reason); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						if (newReasons !== undefined) { | 
					
						
							|  |  |  | 							module.reasons = newReasons; | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  | 	static moduleHasSideEffects(moduleName, flagValue) { | 
					
						
							| 
									
										
										
										
											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": | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (process.platform === "win32") { | 
					
						
							| 
									
										
										
										
											2018-02-21 00:36:14 +08:00
										 |  |  | 					flagValue = flagValue.replace(/\\/g, "/"); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return mm.isMatch(moduleName, flagValue, { | 
					
						
							|  |  |  | 					matchBase: true | 
					
						
							|  |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2018-01-19 00:14:19 +08:00
										 |  |  | 			case "object": | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				return flagValue.some(glob => | 
					
						
							|  |  |  | 					SideEffectsFlagPlugin.moduleHasSideEffects(moduleName, glob) | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											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; |