|
|
|
@ -0,0 +1,190 @@
|
|
|
|
|
/* |
|
|
|
|
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); |
|
|
|
|
}; |