| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency"); | 
					
						
							|  |  |  | const HarmonyImportSideEffectDependency = require("../dependencies/HarmonyImportSideEffectDependency"); | 
					
						
							|  |  |  | const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 19:35:25 +08:00
										 |  |  | class SideEffectsFlagPlugin { | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 	apply(compiler) { | 
					
						
							| 
									
										
										
										
											2017-12-06 22:01:25 +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; | 
					
						
							|  |  |  | 				if(resolveData && resolveData.descriptionFileData && resolveData.relativePath) { | 
					
						
							| 
									
										
										
										
											2017-10-12 23:32:41 +08:00
										 |  |  | 					const sideEffects = resolveData.descriptionFileData.sideEffects; | 
					
						
							| 
									
										
										
										
											2017-09-14 19:35:25 +08:00
										 |  |  | 					const isSideEffectFree = sideEffects === false; // TODO allow more complex expressions
 | 
					
						
							|  |  |  | 					if(isSideEffectFree) { | 
					
						
							| 
									
										
										
										
											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) => { | 
					
						
							|  |  |  | 				if(data.settings.sideEffects === false) | 
					
						
							|  |  |  | 					module.factoryMeta.sideEffectFree = true; | 
					
						
							|  |  |  | 				else if(data.settings.sideEffects === true) | 
					
						
							|  |  |  | 					module.factoryMeta.sideEffectFree = false; | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-12-06 22:01:25 +08:00
										 |  |  | 		compiler.hooks.compilation.tap("SideEffectsFlagPlugin", (compilation) => { | 
					
						
							|  |  |  | 			compilation.hooks.optimizeDependencies.tap("SideEffectsFlagPlugin", (modules) => { | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 				const reexportMaps = new Map(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 19:35:25 +08:00
										 |  |  | 				// Capture reexports of sideEffectFree modules
 | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 				for(const module of modules) { | 
					
						
							|  |  |  | 					const removeDependencies = []; | 
					
						
							|  |  |  | 					for(const dep of module.dependencies) { | 
					
						
							|  |  |  | 						if(dep instanceof HarmonyImportSideEffectDependency) { | 
					
						
							| 
									
										
										
										
											2017-12-06 19:09:17 +08:00
										 |  |  | 							if(dep.module && dep.module.factoryMeta.sideEffectFree) { | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 								removeDependencies.push(dep); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} else if(dep instanceof HarmonyExportImportedSpecifierDependency) { | 
					
						
							| 
									
										
										
										
											2017-12-06 19:09:17 +08:00
										 |  |  | 							if(module.factoryMeta.sideEffectFree) { | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 								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] | 
					
						
							|  |  |  | 										}); | 
					
						
							|  |  |  | 									} | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					for(const dep of removeDependencies) { | 
					
						
							|  |  |  | 						module.removeDependency(dep); | 
					
						
							|  |  |  | 						dep.module.reasons = dep.module.reasons.filter(r => r.dependency !== dep); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// 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-09-14 19:35:25 +08:00
										 |  |  | 				// Update imports along the reexports from sideEffectFree modules
 | 
					
						
							| 
									
										
										
										
											2017-08-08 15:40:17 +08:00
										 |  |  | 				const updates = []; | 
					
						
							|  |  |  | 				for(const pair of reexportMaps) { | 
					
						
							|  |  |  | 					const module = pair[0]; | 
					
						
							|  |  |  | 					const map = pair[1]; | 
					
						
							|  |  |  | 					for(const reason of module.reasons) { | 
					
						
							|  |  |  | 						const dep = reason.dependency; | 
					
						
							|  |  |  | 						if(dep instanceof HarmonyImportSpecifierDependency) { | 
					
						
							|  |  |  | 							const mapping = map.get(dep.id); | 
					
						
							|  |  |  | 							if(mapping) { | 
					
						
							|  |  |  | 								updates.push({ | 
					
						
							|  |  |  | 									dep, | 
					
						
							|  |  |  | 									mapping, | 
					
						
							|  |  |  | 									module, | 
					
						
							|  |  |  | 									reason | 
					
						
							|  |  |  | 								}); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Execute updates
 | 
					
						
							|  |  |  | 				for(const update of updates) { | 
					
						
							|  |  |  | 					const dep = update.dep; | 
					
						
							|  |  |  | 					const mapping = update.mapping; | 
					
						
							|  |  |  | 					const module = update.module; | 
					
						
							|  |  |  | 					const reason = update.reason; | 
					
						
							|  |  |  | 					dep.module = mapping.module; | 
					
						
							|  |  |  | 					dep.id = mapping.exportName; | 
					
						
							|  |  |  | 					module.removeReason(reason.module, dep); | 
					
						
							|  |  |  | 					mapping.module.addReason(reason.module, dep); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-09-14 19:35:25 +08:00
										 |  |  | module.exports = SideEffectsFlagPlugin; |