mirror of https://github.com/webpack/webpack.git
				
				
				
			
		
			
				
	
	
		
			190 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| /*
 | |
| 	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; });
 | |
| 			entryChunks.forEach(function(chunk) {
 | |
| 				(function x(dups, roots, visited, chunk) {
 | |
| 					var currentDups = [];
 | |
| 					var currentRoots = [];
 | |
| 					chunk.modules.forEach(function(module) {
 | |
| 						if(module.duplicates) {
 | |
| 							var idx = currentDups.indexOf(module.duplicates);
 | |
| 							if(idx >= 0) {
 | |
| 								module.rootDuplicates = currentRoots[idx];
 | |
| 								module.rootDuplicates.push(module);
 | |
| 								module.rootDuplicates.commonModules = mergeCommonModules(module.rootDuplicates.commonModules, module.getAllModuleDependencies());
 | |
| 							} else {
 | |
| 								idx = dups.indexOf(module.duplicates);
 | |
| 								if(idx < 0) {
 | |
| 									module.rootDuplicates = [module];
 | |
| 									module.rootDuplicates.commonModules = module.getAllModuleDependencies();
 | |
| 									module.rootDuplicates.initialCcommonModulesLength = module.rootDuplicates.commonModules.length;
 | |
| 									dups = dups.concat([module.duplicates]);
 | |
| 									roots = roots.concat([module.rootDuplicates]);
 | |
| 									currentDups = currentDups.concat([module.duplicates]);
 | |
| 									currentRoots = currentRoots.concat([module.rootDuplicates]);
 | |
| 								} else {
 | |
| 									module.rootDuplicates = roots[idx];
 | |
| 									module.rootDuplicates.commonModules = mergeCommonModules(module.rootDuplicates.commonModules, module.getAllModuleDependencies());
 | |
| 								}
 | |
| 							}
 | |
| 						}
 | |
| 					});
 | |
| 					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;
 | |
| 						var initialLength = roots.initialCcommonModulesLength;
 | |
| 						if(initialLength !== commonModules.length) {
 | |
| 							var template = roots[0].createTemplate(commonModules);
 | |
| 							roots.template = template;
 | |
| 							chunk.addModule(template);
 | |
| 							template.addChunk(chunk);
 | |
| 							compilation.modules.push(template);
 | |
| 						}
 | |
| 					});
 | |
| 				}([], [], [], chunk));
 | |
| 			});
 | |
| 		});
 | |
| 		function mergeCommonModules(commonModules, newModules) {
 | |
| 			return commonModules.filter(function(module) {
 | |
| 				return newModules.indexOf(module) >= 0;
 | |
| 			});
 | |
| 		}
 | |
| 	});
 | |
| 	compiler.moduleTemplate = new DedupModuleTemplateDecorator(compiler.moduleTemplate);
 | |
| 	compiler.mainTemplate.renderAddModule = function(hash, chunk, varModuleId, varModule) {
 | |
| 		return [
 | |
| 			"var _m = " + varModule + ";",
 | |
| 			"switch(typeof _m) {",
 | |
| 			"case \"number\":",
 | |
| 			this.indent([
 | |
| 				"modules[" + varModuleId + "] = modules[_m];",
 | |
| 				"break;"
 | |
| 			]),
 | |
| 			"case \"object\":",
 | |
| 			this.indent([
 | |
| 				"modules[" + varModuleId + "] = (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));"
 | |
| 					]),
 | |
| 					"};"
 | |
| 				]),
 | |
| 				"}(_m));",
 | |
| 				"break;"
 | |
| 			]),
 | |
| 			"default:",
 | |
| 			this.indent("modules[" + varModuleId + "] = _m;"),
 | |
| 			"}"
 | |
| 		]
 | |
| 	};
 | |
| 	var oldRenderModules = compiler.mainTemplate.renderModules;
 | |
| 	compiler.mainTemplate.renderModules = function renderModules(hash, chunk, moduleTemplate, dependencyTemplates) {
 | |
| 		var source = new ConcatSource();
 | |
| 		source.add("(function(modules) {\n");
 | |
| 		source.add(this.indent([
 | |
| 			"for(var i in modules) {",
 | |
| 			this.indent([
 | |
| 				"switch(typeof modules[i]) {",
 | |
| 				"case \"number\":",
 | |
| 				this.indent([
 | |
| 					"modules[i] = modules[modules[i]];",
 | |
| 					"break;"
 | |
| 				]),
 | |
| 				"case \"object\":",
 | |
| 				this.indent([
 | |
| 					"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}(");
 | |
| 		source.add(oldRenderModules.call(this, hash, chunk, moduleTemplate, dependencyTemplates));
 | |
| 		source.add("))");
 | |
| 		return source;
 | |
| 	};
 | |
| };
 | |
| 
 | |
| function DedupModuleTemplateDecorator(template) {
 | |
| 	this.template = template;
 | |
| }
 | |
| 
 | |
| DedupModuleTemplateDecorator.prototype.render = function(module, dependencyTemplates) {
 | |
| 	if(!module.rootDuplicates) return this.template.render(module, dependencyTemplates);
 | |
| 	if(module.rootDuplicates.template) {
 | |
| 		module.rootDuplicates.template.addReason(module, {
 | |
| 			type: "template",
 | |
| 			request: module.request,
 | |
| 			templateModules: module.rootDuplicates.template.templateModules
 | |
| 		});
 | |
| 		var array = [module.rootDuplicates.template.id].concat(module.getTemplateArguments(module.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 {
 | |
| 		module.rootDuplicates.sort(function(a, b) {
 | |
| 			return a.id - b.id;
 | |
| 		});
 | |
| 		if(module === module.rootDuplicates[0]) return this.template.render(module, dependencyTemplates);
 | |
| 		var source = new ConcatSource("" + module.rootDuplicates[0].id);
 | |
| 		return source;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| DedupModuleTemplateDecorator.prototype.updateHash = function(hash) {
 | |
| 	hash.update("DedupModuleTemplateDecorator");
 | |
| 	this.template.updateHash(hash);
 | |
| }; |