Skip to content

Commit c30f16f

Browse files
committed
added experimental deduplication support webpack#47
1 parent 7df05c7 commit c30f16f

22 files changed

+361
-18
lines changed

bin/config-optimist.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ module.exports = function(optimist) {
6161

6262
.boolean("optimize-occurence-order").describe("optimize-occurence-order")
6363

64+
.boolean("optimize-dedupe").describe("optimize-dedupe")
65+
6466
.string("prefetch").describe("prefetch")
6567

6668
.string("provide").describe("provide")

bin/convert-argv.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,11 @@ module.exports = function(optimist, argv, convertOptions) {
267267
options.optimize.occurenceOrder = true;
268268
});
269269

270+
ifBooleanArg("optimize-dedupe", function() {
271+
ensureObject(options, "optimize");
272+
options.optimize.dedupe = true;
273+
});
274+
270275
ifArg("prefetch", function(request) {
271276
ensureArray(options, "prefetch");
272277
options.prefetch.push(request);

lib/FunctionModuleTemplate.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ FunctionModuleTemplate.prototype.render = function(module, dependencyTemplates)
1919
source.add(" !*** " + req.replace(/\*\//g, "*_/") + " ***!\n");
2020
source.add(" \\****" + req.replace(/./g, "*") + "****/\n");
2121
}
22-
source.add("/***/ function(module, exports, require) {\n\n");
22+
source.add("/***/ function(" + ["module", "exports", "require"].concat(module.arguments || []).join(", ") + ") {\n\n");
2323
source.add(new PrefixSource("\t", module.source(dependencyTemplates, this.outputOptions, this.requestShortener)));
2424
source.add("\n\n/***/ }");
2525
return source;

lib/JsonpMainTemplate.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ JsonpMainTemplate.prototype.renderInit = function(hash, chunk) {
8484
"installedChunks[chunkId] = 0;"
8585
]),
8686
"}",
87-
"for(moduleId in moreModules)",
88-
this.indent("modules[moduleId] = moreModules[moduleId];"),
87+
"for(moduleId in moreModules) {",
88+
this.indent(this.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")),
89+
"}",
8990
"while(callbacks.length)",
9091
this.indent("callbacks.shift().call(null, require);"),
9192
]),

lib/MainTemplate.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,24 @@ MainTemplate.prototype.render = function(hash, chunk, moduleTemplate, dependency
3333
source.add(new PrefixSource("/******/ \t", new OriginalSource(this.asString(buf), "webpackBootstrap " + hash)));
3434
source.add("\n/******/ })\n");
3535
source.add("/************************************************************************/\n");
36-
source.add("/******/ ({\n");
36+
source.add("/******/ (");
37+
source.add(this.renderModules(hash, chunk, moduleTemplate, dependencyTemplates));
38+
source.add(")");
39+
chunk.rendered = true;
40+
return source;
41+
};
42+
43+
MainTemplate.prototype.renderModules = function renderModules(hash, chunk, moduleTemplate, dependencyTemplates) {
44+
var source = new ConcatSource();
45+
source.add("{\n");
3746
source.add(this.asString(this.renderInitModules(hash, chunk, moduleTemplate, dependencyTemplates)));
3847
source.add("\n");
3948
chunk.modules.forEach(function(module, idx) {
4049
if(idx != 0) source.add(",\n");
4150
source.add("\n/***/ " + module.id + ":\n");
4251
source.add(moduleTemplate.render(module, dependencyTemplates));
4352
});
44-
source.add("\n/******/ })");
45-
chunk.rendered = true;
53+
source.add("\n/******/ }");
4654
return source;
4755
};
4856

@@ -138,6 +146,10 @@ MainTemplate.prototype.renderInitModules = function(hash, chunk, moduleTemplate,
138146
];
139147
};
140148

149+
MainTemplate.prototype.renderAddModule = function(hash, chunk, varModuleId, varModule) {
150+
return ["modules[" + varModuleId + "] = " + varModule + ";"]
151+
}
152+
141153
MainTemplate.prototype.updateHash = function(hash) {
142154
hash.update("maintemplate");
143155
hash.update("1");

lib/Module.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@ module.exports = Module;
2323

2424
Module.prototype = Object.create(DependenciesBlock.prototype);
2525

26-
Module.prototype.separable = function(callback) {
27-
callback(false);
28-
};
29-
3026
Module.prototype.disconnect = function() {
3127
this.reasons.length = 0;
3228
this.lastId = this.id;

lib/NormalModule.js

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ var OriginalSource = require("webpack-core/lib/OriginalSource");
99
var RawSource = require("webpack-core/lib/RawSource");
1010
var ReplaceSource = require("webpack-core/lib/ReplaceSource");
1111
var ModuleParseError = require("./ModuleParseError");
12+
var TemplateArgumentDependency = require("./dependencies/TemplateArgumentDependency");
1213
var path = require("path");
1314

1415
function NormalModule(request, userRequest, rawRequest, loaders, resource, parser) {
@@ -82,7 +83,7 @@ NormalModule.prototype.source = function(dependencyTemplates, outputOptions, req
8283
function doDep(dep) {
8384
var template = dependencyTemplates.get(dep.Class);
8485
if(!template) throw new Error("No template for dependency: " + dep.Class.name);
85-
template.apply(dep, source, outputOptions, requestShortener);
86+
template.apply(dep, source, outputOptions, requestShortener, dependencyTemplates);
8687
}
8788
function doVariable(vars, variable) {
8889
var name = variable.name;
@@ -151,3 +152,82 @@ NormalModule.prototype.updateHash = function(hash) {
151152
hash.update("null");
152153
Module.prototype.updateHash.call(this, hash);
153154
};
155+
156+
NormalModule.prototype.getSourceHash = function() {
157+
if(!this._source) return "";
158+
var hash = new (require("crypto").Hash)("md5");
159+
hash.update(this._source.source());
160+
return hash.digest("hex");
161+
};
162+
163+
NormalModule.prototype.getAllModuleDependencies = function() {
164+
var list = [];
165+
function doDep(dep) {
166+
if(dep.module && list.indexOf(dep.module) < 0)
167+
list.push(dep.module);
168+
}
169+
function doVariable(variable) {
170+
variable.dependencies.forEach(doDep);
171+
}
172+
function doBlock(block) {
173+
block.variables.forEach(doVariable);
174+
block.dependencies.forEach(doDep);
175+
block.blocks.forEach(doBlock);
176+
}
177+
doBlock(this);
178+
return list;
179+
};
180+
181+
NormalModule.prototype.createTemplate = function(keepModules) {
182+
var template = new NormalModule("", "", "", [], "", null);
183+
template._source = this._source;
184+
template.built = this.built;
185+
template.templateModules = keepModules;
186+
var args = template.arguments = [];
187+
function doDeps(deps) {
188+
return deps.map(function(dep) {
189+
if(keepModules.indexOf(dep.module) < 0) {
190+
var argName = "__webpack_module_template_argument_" + args.length + "__";
191+
args.push(argName);
192+
return new TemplateArgumentDependency(argName, dep);
193+
} else {
194+
return dep;
195+
}
196+
});
197+
}
198+
function doVariable(variable, newVariable) {
199+
variable.dependencies.forEach(doDep);
200+
}
201+
function doBlock(block, newBlock) {
202+
block.variables.forEach(function(variable) {
203+
var newDependencies = doDeps(variable.dependencies);
204+
newBlock.addVariable(variable.name, variable.expression, newDependencies);
205+
});
206+
newBlock.dependencies = doDeps(block.dependencies);
207+
block.blocks.forEach(function(childBlock) {
208+
var newChildBlock = new AsyncDependenciesBlock(childBlock.name);
209+
newBlock.addBlock(newChildBlock);
210+
doBlock(childBlock, newChildBlock);
211+
});
212+
}
213+
doBlock(this, template);
214+
return template;
215+
};
216+
217+
NormalModule.prototype.getTemplateArguments = function(keepModules) {
218+
var list = [];
219+
function doDep(dep) {
220+
if(dep.module && keepModules.indexOf(dep.module) < 0)
221+
list.push(dep.module);
222+
}
223+
function doVariable(variable) {
224+
variable.dependencies.forEach(doDep);
225+
}
226+
function doBlock(block) {
227+
block.variables.forEach(doVariable);
228+
block.dependencies.forEach(doDep);
229+
block.blocks.forEach(doBlock);
230+
}
231+
doBlock(this);
232+
return list;
233+
};

lib/Stats.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ Stats.prototype.toJson = function toJson(options, forToString) {
135135
userRequest: reason.dependency.userRequest
136136
}
137137
var dep = reason.dependency;
138+
if(dep.templateModules) obj.templateModules = dep.templateModules.map(function(module) { return module.id; });
138139
if(dep.loc) obj.loc = dep.loc.start.line + ":" + dep.loc.start.column + "-" +
139140
(dep.loc.start.line != dep.loc.end.line ? dep.loc.end.line + ":" : "") + dep.loc.end.column
140141
return obj;
@@ -436,6 +437,7 @@ Stats.jsonToString = function jsonToString(obj, useColors) {
436437
normal(reason.type);
437438
normal(" ");
438439
cyan(reason.userRequest);
440+
if(reason.templateModules) cyan(reason.templateModules.join(" "));
439441
normal(" [");
440442
normal(reason.moduleId);
441443
normal("] ");
@@ -469,6 +471,7 @@ Stats.jsonToString = function jsonToString(obj, useColors) {
469471
normal(reason.type);
470472
normal(" ");
471473
cyan(reason.userRequest);
474+
if(reason.templateModules) cyan(reason.templateModules.join(" "));
472475
normal(" [");
473476
normal(reason.moduleId);
474477
normal("] ");

lib/WebpackOptionsApply.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ var RemoveParentModulesPlugin = require("./optimize/RemoveParentModulesPlugin");
4242
var RemoveEmptyChunksPlugin = require("./optimize/RemoveEmptyChunksPlugin");
4343
var MergeDuplicateChunksPlugin = require("./optimize/MergeDuplicateChunksPlugin");
4444
var FlagIncludedChunksPlugin = require("./optimize/FlagIncludedChunksPlugin");
45+
var DedupePlugin = require("./optimize/DedupePlugin");
4546

4647
var ModulesInDirectoriesPlugin = require("enhanced-resolve/lib/ModulesInDirectoriesPlugin");
4748
var ModulesInRootPlugin = require("enhanced-resolve/lib/ModulesInRootPlugin");
@@ -156,6 +157,9 @@ WebpackOptionsApply.prototype.process = function(options, compiler) {
156157
else if(options.optimize.minimize)
157158
compiler.apply(new UglifyJsPlugin(options.optimize.minimize));
158159

160+
if(options.optimize.dedupe === true)
161+
compiler.apply(new DedupePlugin());
162+
159163
if(options.cache === undefined ? options.watch : options.cache)
160164
compiler.apply(new CachePlugin(typeof options.cache == "object" ? options.cache : null));
161165

lib/dependencies/ModuleDependencyTemplateAsId.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,7 @@ ModuleDependencyTemplateAsId.prototype.apply = function(dep, source, outputOptio
1414
var content = "(function webpackMissingModule() { throw new Error(" + JSON.stringify("Cannot find module \"" + dep.request + "\"") + "); }())";
1515
source.replace(dep.range[0], dep.range[1]-1, content);
1616
};
17+
18+
ModuleDependencyTemplateAsId.prototype.applyAsTemplateArgument = function(name, dep, source, outputOptions, requestShortener) {
19+
source.replace(dep.range[0], dep.range[1]-1, name);
20+
};

0 commit comments

Comments
 (0)