orionsoft-react-scripts
Version:
Orionsoft Configuration and scripts for Create React App.
228 lines (220 loc) • 8.36 kB
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-tree", function(chunks, modules) {
var modulesByHash = {};
var allDups = [];
modules.forEach(function(module) {
if(!module.getSourceHash || !module.getAllModuleDependencies || !module.createTemplate || !module.getTemplateArguments || module.blocks.length > 0) 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;
}
});
var entryChunks = chunks.filter(function(c) {
return c.entry;
});
entryChunks.forEach(function(chunk) { // for each entry chunk
var hasDeduplicatedModules = false;
(function x(dups, roots, visited, chunk) {
var currentDups = [];
var currentRoots = [];
chunk.modules.forEach(function(module) {
if(module.duplicates) {
if(!module.rootDuplicatesChunks)
module.rootDuplicatesChunks = module.chunks.slice();
var chunkIndex = module.rootDuplicatesChunks.indexOf(chunk);
if(!module.rootDuplicates) module.rootDuplicates = [];
var idx = currentDups.indexOf(module.duplicates);
if(idx >= 0) {
module.rootDuplicates[chunkIndex] = currentRoots[idx];
module.rootDuplicates[chunkIndex].push(module);
module.rootDuplicates[chunkIndex].commonModules =
mergeCommonModules(module.rootDuplicates[chunkIndex].commonModules, module.getAllModuleDependencies());
hasDeduplicatedModules = true;
} else {
idx = dups.indexOf(module.duplicates);
if(idx < 0) {
module.rootDuplicates[chunkIndex] = [module];
module.rootDuplicates[chunkIndex].commonModules = module.getAllModuleDependencies();
module.rootDuplicates[chunkIndex].initialCommonModulesLength = module.rootDuplicates[chunkIndex].commonModules.length;
dups = dups.concat([module.duplicates]);
roots = roots.concat([module.rootDuplicates[chunkIndex]]);
currentDups = currentDups.concat([module.duplicates]);
currentRoots = currentRoots.concat([module.rootDuplicates[chunkIndex]]);
} else {
module.rootDuplicates[chunkIndex] = roots[idx];
module.rootDuplicates[chunkIndex].commonModules =
mergeCommonModules(module.rootDuplicates[chunkIndex].commonModules, module.getAllModuleDependencies());
hasDeduplicatedModules = true;
}
}
}
});
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.initialCommonModulesLength;
if(initialLength !== commonModules.length) {
var template = roots[0].createTemplate(commonModules, roots.slice());
roots.template = template;
chunk.addModule(template);
template.addChunk(chunk);
compilation.modules.push(template);
hasDeduplicatedModules = true;
}
});
}([], [], [], chunk));
if(hasDeduplicatedModules)
chunk.__DedupePluginHasDeduplicatedModules = true;
});
});
function mergeCommonModules(commonModules, newModules) {
return commonModules.filter(function(module) {
return newModules.indexOf(module) >= 0;
});
}
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) {
if(a.request === b.request) return 0;
return a.request < b.request ? -1 : 1;
});
var array = [JSON.stringify(rootDuplicates.template.id)].concat(module.getTemplateArguments(rootDuplicates.template.templateModules).map(function(module) {
if(module.id === null || module.id === undefined)
return "(function webpackMissingModule() { throw new Error(" + JSON.stringify("Cannot find module") + "); }())";
return JSON.stringify(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("" + JSON.stringify(rootDuplicates[0].id));
return source;
}
});
compilation.plugin("chunk-hash", function(chunk, hash) {
if(chunk.__DedupePluginHasDeduplicatedModules)
hash.update("DedupePlugin (deduplication code)");
});
compilation.mainTemplate.plugin("add-module", function(source, chunk, hash, varModuleId, varModule) {
// we don't need to test all nested chunks, because `__DedupePluginHasDeduplicatedModules`
// is not set on entry chunks
if(!chunk.__DedupePluginHasDeduplicatedModules) {
return source;
}
return this.asString([
"var _m = " + varModule + ";",
"",
"// Check if module is deduplicated",
"switch(typeof _m) {",
"case \"object\":",
this.indent([
"// Module can be created from a template",
"modules[" + varModuleId + "] = (function(_m) {",
this.indent([
"var args = _m.slice(1), templateId = _m[0];",
"return function (a,b,c) {",
this.indent([
"modules[templateId].apply(this, [a,b,c].concat(args));"
]),
"};"
]),
"}(_m));",
"break;"
]),
"case \"function\":",
this.indent([
"// Normal module",
"modules[" + varModuleId + "] = _m;",
"break;"
]),
"default:",
this.indent([
"// Module is a copy of another module",
"modules[" + varModuleId + "] = modules[_m];",
"break;"
]),
"}"
]);
});
compilation.mainTemplate.plugin("modules", function(orginalSource, chunk) {
if(!chunk.__DedupePluginHasDeduplicatedModules) {
return orginalSource;
}
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([
"if(Object.prototype.hasOwnProperty.call(modules, i)) {",
this.indent([
"switch(typeof modules[i]) {",
"case \"function\": 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(this, [a,b,c].concat(args));"
]),
"};"
]),
"}(modules[i]));",
"break;"
]),
"default:",
this.indent([
"// Module is a copy of another module",
"modules[i] = modules[modules[i]];",
"break;"
]),
"}"
]),
"}"
]),
"}",
"return modules;"
]));
source.add("\n}(");
source.add(orginalSource);
source.add("))");
return source;
});
});
};