| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | var ConcatSource = require("webpack-core/lib/ConcatSource"); | 
					
						
							|  |  |  | var TemplateArgumentDependency = require("../dependencies/TemplateArgumentDependency"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function DedupePlugin() { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module.exports = DedupePlugin; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DedupePlugin.prototype.apply = function(compiler) { | 
					
						
							|  |  |  | 	compiler.plugin("compilation", function(compilation) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		compilation.dependencyTemplates.set(TemplateArgumentDependency, new TemplateArgumentDependency.Template()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		compilation.plugin("after-optimize-modules", function(modules) { | 
					
						
							|  |  |  | 			var modulesByHash = {}; | 
					
						
							|  |  |  | 			var allDups = []; | 
					
						
							|  |  |  | 			modules.forEach(function(module, idx) { | 
					
						
							|  |  |  | 				if(!module.getSourceHash || !module.getAllModuleDependencies || !module.createTemplate || !module.getTemplateArguments) return; | 
					
						
							|  |  |  | 				var hash = module.getSourceHash(); | 
					
						
							|  |  |  | 				var dupModule = modulesByHash[hash]; | 
					
						
							|  |  |  | 				if(dupModule) { | 
					
						
							|  |  |  | 					if(dupModule.duplicates) { | 
					
						
							|  |  |  | 						dupModule.duplicates.push(module); | 
					
						
							|  |  |  | 						module.duplicates = dupModule.duplicates; | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						allDups.push(module.duplicates = dupModule.duplicates = [dupModule, module]); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					modulesByHash[hash] = module; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		compilation.plugin("after-optimize-chunks", function(chunks) { | 
					
						
							|  |  |  | 			var entryChunks = chunks.filter(function(c) { return c.entry; }); | 
					
						
							| 
									
										
										
										
											2013-06-14 21:13:44 +08:00
										 |  |  | 			entryChunks.forEach(function(chunk) { // for each entry chunk
 | 
					
						
							| 
									
										
										
										
											2013-06-14 21:42:40 +08:00
										 |  |  | 				var hasDeduplicatedModules = false; | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 				(function x(dups, roots, visited, chunk) { | 
					
						
							|  |  |  | 					var currentDups = []; | 
					
						
							|  |  |  | 					var currentRoots = []; | 
					
						
							|  |  |  | 					chunk.modules.forEach(function(module) { | 
					
						
							|  |  |  | 						if(module.duplicates) { | 
					
						
							| 
									
										
										
										
											2013-06-14 21:13:44 +08:00
										 |  |  | 							if(!module.rootDuplicatesChunks) | 
					
						
							|  |  |  | 								module.rootDuplicatesChunks = module.chunks.slice(); | 
					
						
							|  |  |  | 							var chunkIndex = module.rootDuplicatesChunks.indexOf(chunk); | 
					
						
							|  |  |  | 							if(!module.rootDuplicates) module.rootDuplicates = []; | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 							var idx = currentDups.indexOf(module.duplicates); | 
					
						
							|  |  |  | 							if(idx >= 0) { | 
					
						
							| 
									
										
										
										
											2013-06-14 21:13:44 +08:00
										 |  |  | 								module.rootDuplicates[chunkIndex] = currentRoots[idx]; | 
					
						
							|  |  |  | 								module.rootDuplicates[chunkIndex].push(module); | 
					
						
							|  |  |  | 								module.rootDuplicates[chunkIndex].commonModules = | 
					
						
							|  |  |  | 									mergeCommonModules(module.rootDuplicates[chunkIndex].commonModules, module.getAllModuleDependencies()); | 
					
						
							| 
									
										
										
										
											2013-06-14 21:42:40 +08:00
										 |  |  | 								hasDeduplicatedModules = true; | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 							} else { | 
					
						
							|  |  |  | 								idx = dups.indexOf(module.duplicates); | 
					
						
							|  |  |  | 								if(idx < 0) { | 
					
						
							| 
									
										
										
										
											2013-06-14 21:13:44 +08:00
										 |  |  | 									module.rootDuplicates[chunkIndex] = [module]; | 
					
						
							|  |  |  | 									module.rootDuplicates[chunkIndex].commonModules = module.getAllModuleDependencies(); | 
					
						
							|  |  |  | 									module.rootDuplicates[chunkIndex].initialCommonModulesLength = module.rootDuplicates[chunkIndex].commonModules.length; | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 									dups = dups.concat([module.duplicates]); | 
					
						
							| 
									
										
										
										
											2013-06-14 21:13:44 +08:00
										 |  |  | 									roots = roots.concat([module.rootDuplicates[chunkIndex]]); | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 									currentDups = currentDups.concat([module.duplicates]); | 
					
						
							| 
									
										
										
										
											2013-06-14 21:13:44 +08:00
										 |  |  | 									currentRoots = currentRoots.concat([module.rootDuplicates[chunkIndex]]); | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 								} else { | 
					
						
							| 
									
										
										
										
											2013-06-14 21:13:44 +08:00
										 |  |  | 									module.rootDuplicates[chunkIndex] = roots[idx]; | 
					
						
							|  |  |  | 									module.rootDuplicates[chunkIndex].commonModules = | 
					
						
							|  |  |  | 										mergeCommonModules(module.rootDuplicates[chunkIndex].commonModules, module.getAllModuleDependencies()); | 
					
						
							| 
									
										
										
										
											2013-06-14 21:42:40 +08:00
										 |  |  | 									hasDeduplicatedModules = true; | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					chunk.chunks.forEach(function(chunk) { | 
					
						
							|  |  |  | 						if(visited.indexOf(chunk) < 0) | 
					
						
							|  |  |  | 							x(dups, roots, visited.concat(chunk), chunk); | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					currentRoots.forEach(function(roots) { | 
					
						
							|  |  |  | 						var commonModules = roots.commonModules; | 
					
						
							| 
									
										
										
										
											2013-06-14 21:13:44 +08:00
										 |  |  | 						var initialLength = roots.initialCommonModulesLength; | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 						if(initialLength !== commonModules.length) { | 
					
						
							|  |  |  | 							var template = roots[0].createTemplate(commonModules); | 
					
						
							|  |  |  | 							roots.template = template; | 
					
						
							|  |  |  | 							chunk.addModule(template); | 
					
						
							|  |  |  | 							template.addChunk(chunk); | 
					
						
							|  |  |  | 							compilation.modules.push(template); | 
					
						
							| 
									
										
										
										
											2013-06-14 21:42:40 +08:00
										 |  |  | 							hasDeduplicatedModules = true; | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				}([], [], [], chunk)); | 
					
						
							| 
									
										
										
										
											2013-06-14 21:42:40 +08:00
										 |  |  | 				if(hasDeduplicatedModules) | 
					
						
							|  |  |  | 					chunk._DedupePlugin_hasDeduplicatedModules = true; | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		function mergeCommonModules(commonModules, newModules) { | 
					
						
							|  |  |  | 			return commonModules.filter(function(module) { | 
					
						
							|  |  |  | 				return newModules.indexOf(module) >= 0; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-09 15:43:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-03 14:45:26 +08:00
										 |  |  | 		compilation.moduleTemplate.plugin("package", function(moduleSource, module, chunk) { | 
					
						
							|  |  |  | 			if(!module.rootDuplicatesChunks || !chunk) return moduleSource; | 
					
						
							|  |  |  | 			var chunkIndex = module.rootDuplicatesChunks.indexOf(chunk); | 
					
						
							|  |  |  | 			if(!module.rootDuplicates || !module.rootDuplicates[chunkIndex]) return moduleSource; | 
					
						
							|  |  |  | 			var rootDuplicates = module.rootDuplicates[chunkIndex]; | 
					
						
							|  |  |  | 			if(rootDuplicates.template) { | 
					
						
							|  |  |  | 				rootDuplicates.template.addReason(module, { | 
					
						
							|  |  |  | 					type: "template", | 
					
						
							|  |  |  | 					request: module.request, | 
					
						
							|  |  |  | 					templateModules: rootDuplicates.template.templateModules | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				rootDuplicates.template.reasons.sort(function(a, b) { | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 					if(a.request === b.request) return 0; | 
					
						
							| 
									
										
										
										
											2014-06-03 14:45:26 +08:00
										 |  |  | 					return a.request < b.request ? -1 : 1; | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				var array = [rootDuplicates.template.id].concat(module.getTemplateArguments(rootDuplicates.template.templateModules).map(function(module) { | 
					
						
							|  |  |  | 					if(typeof module.id !== "number") | 
					
						
							|  |  |  | 						return "(function webpackMissingModule() { throw new Error(" + JSON.stringify("Cannot find module") + "); }())" | 
					
						
							|  |  |  | 					return module.id; | 
					
						
							|  |  |  | 				})); | 
					
						
							|  |  |  | 				var source = new ConcatSource("[" + array.join(", ") + "]"); | 
					
						
							|  |  |  | 				return source; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				rootDuplicates.sort(function(a, b) { | 
					
						
							|  |  |  | 					return a.id - b.id; | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				if(module === rootDuplicates[0]) return moduleSource; | 
					
						
							|  |  |  | 				var source = new ConcatSource("" + rootDuplicates[0].id); | 
					
						
							|  |  |  | 				return source; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2015-02-09 15:43:46 +08:00
										 |  |  | 		compilation.plugin("chunk-hash", function(chunk, hash) { | 
					
						
							|  |  |  | 			if(chunk._DedupePlugin_hasDeduplicatedModules) | 
					
						
							|  |  |  | 				hash.update("DedupePlugin (deduplication code)"); | 
					
						
							| 
									
										
										
										
											2014-06-03 14:45:26 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2014-06-03 03:23:53 +08:00
										 |  |  | 		compilation.mainTemplate.plugin("add-module", function(source, chunk, hash, varModuleId, varModule) { | 
					
						
							| 
									
										
										
										
											2015-02-09 15:43:46 +08:00
										 |  |  | 			// we don't need to test all nested chunks, because `_DedupePlugin_hasDeduplicatedModules`
 | 
					
						
							|  |  |  | 			// is not set on entry chunks
 | 
					
						
							| 
									
										
										
										
											2013-12-18 06:21:49 +08:00
										 |  |  | 			if(!chunk._DedupePlugin_hasDeduplicatedModules) { | 
					
						
							| 
									
										
										
										
											2014-06-03 03:23:53 +08:00
										 |  |  | 				return source; | 
					
						
							| 
									
										
										
										
											2013-12-18 06:21:49 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-06-03 03:23:53 +08:00
										 |  |  | 			return this.asString([ | 
					
						
							| 
									
										
										
										
											2013-12-18 06:21:49 +08:00
										 |  |  | 				"var _m = " + varModule + ";", | 
					
						
							|  |  |  | 				"", | 
					
						
							|  |  |  | 				"// Check if module is deduplicated", | 
					
						
							|  |  |  | 				"switch(typeof _m) {", | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 				"case \"number\":", | 
					
						
							|  |  |  | 				this.indent([ | 
					
						
							| 
									
										
										
										
											2013-06-14 21:42:40 +08:00
										 |  |  | 					"// Module is a copy of another module", | 
					
						
							| 
									
										
										
										
											2013-12-18 06:21:49 +08:00
										 |  |  | 					"modules[" + varModuleId + "] = modules[_m];", | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 					"break;" | 
					
						
							|  |  |  | 				]), | 
					
						
							|  |  |  | 				"case \"object\":", | 
					
						
							|  |  |  | 				this.indent([ | 
					
						
							| 
									
										
										
										
											2013-06-14 21:42:40 +08:00
										 |  |  | 					"// Module can be created from a template", | 
					
						
							| 
									
										
										
										
											2013-12-18 06:21:49 +08:00
										 |  |  | 					"modules[" + varModuleId + "] = (function(_m) {", | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 					this.indent([ | 
					
						
							| 
									
										
										
										
											2014-07-17 03:26:21 +08:00
										 |  |  | 						"var args = _m.slice(1), templateId = _m[0];", | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 						"return function (a,b,c) {", | 
					
						
							|  |  |  | 						this.indent([ | 
					
						
							| 
									
										
										
										
											2014-07-17 03:26:21 +08:00
										 |  |  | 							"modules[templateId].apply(this, [a,b,c].concat(args));" | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 						]), | 
					
						
							|  |  |  | 						"};" | 
					
						
							|  |  |  | 					]), | 
					
						
							| 
									
										
										
										
											2013-12-18 06:21:49 +08:00
										 |  |  | 					"}(_m));", | 
					
						
							|  |  |  | 					"break;" | 
					
						
							|  |  |  | 				]), | 
					
						
							|  |  |  | 				"default:", | 
					
						
							|  |  |  | 				this.indent([ | 
					
						
							|  |  |  | 					"// Normal module", | 
					
						
							|  |  |  | 					"modules[" + varModuleId + "] = _m;" | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | 				]), | 
					
						
							|  |  |  | 				"}" | 
					
						
							| 
									
										
										
										
											2014-06-03 03:23:53 +08:00
										 |  |  | 			]); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		compilation.mainTemplate.plugin("modules", function(orginalSource, chunk, hash, moduleTemplate, dependencyTemplates) { | 
					
						
							| 
									
										
										
										
											2013-12-18 06:21:49 +08:00
										 |  |  | 			if(!chunk._DedupePlugin_hasDeduplicatedModules) { | 
					
						
							| 
									
										
										
										
											2014-06-03 03:23:53 +08:00
										 |  |  | 				return orginalSource; | 
					
						
							| 
									
										
										
										
											2013-12-18 06:21:49 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			var source = new ConcatSource(); | 
					
						
							|  |  |  | 			source.add("(function(modules) {\n"); | 
					
						
							|  |  |  | 			source.add(this.indent([ | 
					
						
							|  |  |  | 				"// Check all modules for deduplicated modules", | 
					
						
							|  |  |  | 				"for(var i in modules) {", | 
					
						
							|  |  |  | 				this.indent([ | 
					
						
							|  |  |  | 					"switch(typeof modules[i]) {", | 
					
						
							|  |  |  | 					"case \"number\":", | 
					
						
							|  |  |  | 					this.indent([ | 
					
						
							|  |  |  | 						"// Module is a copy of another module", | 
					
						
							|  |  |  | 						"modules[i] = modules[modules[i]];", | 
					
						
							|  |  |  | 						"break;" | 
					
						
							|  |  |  | 					]), | 
					
						
							|  |  |  | 					"case \"object\":", | 
					
						
							|  |  |  | 					this.indent([ | 
					
						
							|  |  |  | 						"// Module can be created from a template", | 
					
						
							|  |  |  | 						"modules[i] = (function(_m) {", | 
					
						
							|  |  |  | 						this.indent([ | 
					
						
							|  |  |  | 							"var args = _m.slice(1), fn = modules[_m[0]];", | 
					
						
							|  |  |  | 							"return function (a,b,c) {", | 
					
						
							|  |  |  | 							this.indent([ | 
					
						
							|  |  |  | 								"fn.apply(null, [a,b,c].concat(args));" | 
					
						
							|  |  |  | 							]), | 
					
						
							|  |  |  | 							"};" | 
					
						
							|  |  |  | 						]), | 
					
						
							|  |  |  | 						"}(modules[i]));" | 
					
						
							|  |  |  | 					]), | 
					
						
							|  |  |  | 					"}" | 
					
						
							|  |  |  | 				]), | 
					
						
							|  |  |  | 				"}", | 
					
						
							|  |  |  | 				"return modules;" | 
					
						
							|  |  |  | 			])); | 
					
						
							|  |  |  | 			source.add("\n}("); | 
					
						
							| 
									
										
										
										
											2014-06-03 03:23:53 +08:00
										 |  |  | 			source.add(orginalSource); | 
					
						
							| 
									
										
										
										
											2013-12-18 06:21:49 +08:00
										 |  |  | 			source.add("))"); | 
					
						
							|  |  |  | 			return source; | 
					
						
							| 
									
										
										
										
											2014-06-03 03:23:53 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2013-12-18 06:21:49 +08:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2013-06-12 22:16:06 +08:00
										 |  |  | }; |