added experimental deduplication support #47

This commit is contained in:
Tobias Koppers 2013-06-12 16:16:06 +02:00
parent 7df05c7ddc
commit c30f16f439
22 changed files with 361 additions and 18 deletions

View File

@ -61,6 +61,8 @@ module.exports = function(optimist) {
.boolean("optimize-occurence-order").describe("optimize-occurence-order") .boolean("optimize-occurence-order").describe("optimize-occurence-order")
.boolean("optimize-dedupe").describe("optimize-dedupe")
.string("prefetch").describe("prefetch") .string("prefetch").describe("prefetch")
.string("provide").describe("provide") .string("provide").describe("provide")

View File

@ -267,6 +267,11 @@ module.exports = function(optimist, argv, convertOptions) {
options.optimize.occurenceOrder = true; options.optimize.occurenceOrder = true;
}); });
ifBooleanArg("optimize-dedupe", function() {
ensureObject(options, "optimize");
options.optimize.dedupe = true;
});
ifArg("prefetch", function(request) { ifArg("prefetch", function(request) {
ensureArray(options, "prefetch"); ensureArray(options, "prefetch");
options.prefetch.push(request); options.prefetch.push(request);

View File

@ -19,7 +19,7 @@ FunctionModuleTemplate.prototype.render = function(module, dependencyTemplates)
source.add(" !*** " + req.replace(/\*\//g, "*_/") + " ***!\n"); source.add(" !*** " + req.replace(/\*\//g, "*_/") + " ***!\n");
source.add(" \\****" + req.replace(/./g, "*") + "****/\n"); source.add(" \\****" + req.replace(/./g, "*") + "****/\n");
} }
source.add("/***/ function(module, exports, require) {\n\n"); source.add("/***/ function(" + ["module", "exports", "require"].concat(module.arguments || []).join(", ") + ") {\n\n");
source.add(new PrefixSource("\t", module.source(dependencyTemplates, this.outputOptions, this.requestShortener))); source.add(new PrefixSource("\t", module.source(dependencyTemplates, this.outputOptions, this.requestShortener)));
source.add("\n\n/***/ }"); source.add("\n\n/***/ }");
return source; return source;

View File

@ -84,8 +84,9 @@ JsonpMainTemplate.prototype.renderInit = function(hash, chunk) {
"installedChunks[chunkId] = 0;" "installedChunks[chunkId] = 0;"
]), ]),
"}", "}",
"for(moduleId in moreModules)", "for(moduleId in moreModules) {",
this.indent("modules[moduleId] = moreModules[moduleId];"), this.indent(this.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")),
"}",
"while(callbacks.length)", "while(callbacks.length)",
this.indent("callbacks.shift().call(null, require);"), this.indent("callbacks.shift().call(null, require);"),
]), ]),

View File

@ -33,7 +33,16 @@ MainTemplate.prototype.render = function(hash, chunk, moduleTemplate, dependency
source.add(new PrefixSource("/******/ \t", new OriginalSource(this.asString(buf), "webpackBootstrap " + hash))); source.add(new PrefixSource("/******/ \t", new OriginalSource(this.asString(buf), "webpackBootstrap " + hash)));
source.add("\n/******/ })\n"); source.add("\n/******/ })\n");
source.add("/************************************************************************/\n"); source.add("/************************************************************************/\n");
source.add("/******/ ({\n"); source.add("/******/ (");
source.add(this.renderModules(hash, chunk, moduleTemplate, dependencyTemplates));
source.add(")");
chunk.rendered = true;
return source;
};
MainTemplate.prototype.renderModules = function renderModules(hash, chunk, moduleTemplate, dependencyTemplates) {
var source = new ConcatSource();
source.add("{\n");
source.add(this.asString(this.renderInitModules(hash, chunk, moduleTemplate, dependencyTemplates))); source.add(this.asString(this.renderInitModules(hash, chunk, moduleTemplate, dependencyTemplates)));
source.add("\n"); source.add("\n");
chunk.modules.forEach(function(module, idx) { chunk.modules.forEach(function(module, idx) {
@ -41,8 +50,7 @@ MainTemplate.prototype.render = function(hash, chunk, moduleTemplate, dependency
source.add("\n/***/ " + module.id + ":\n"); source.add("\n/***/ " + module.id + ":\n");
source.add(moduleTemplate.render(module, dependencyTemplates)); source.add(moduleTemplate.render(module, dependencyTemplates));
}); });
source.add("\n/******/ })"); source.add("\n/******/ }");
chunk.rendered = true;
return source; return source;
}; };
@ -138,6 +146,10 @@ MainTemplate.prototype.renderInitModules = function(hash, chunk, moduleTemplate,
]; ];
}; };
MainTemplate.prototype.renderAddModule = function(hash, chunk, varModuleId, varModule) {
return ["modules[" + varModuleId + "] = " + varModule + ";"]
}
MainTemplate.prototype.updateHash = function(hash) { MainTemplate.prototype.updateHash = function(hash) {
hash.update("maintemplate"); hash.update("maintemplate");
hash.update("1"); hash.update("1");

View File

@ -23,10 +23,6 @@ module.exports = Module;
Module.prototype = Object.create(DependenciesBlock.prototype); Module.prototype = Object.create(DependenciesBlock.prototype);
Module.prototype.separable = function(callback) {
callback(false);
};
Module.prototype.disconnect = function() { Module.prototype.disconnect = function() {
this.reasons.length = 0; this.reasons.length = 0;
this.lastId = this.id; this.lastId = this.id;

View File

@ -9,6 +9,7 @@ var OriginalSource = require("webpack-core/lib/OriginalSource");
var RawSource = require("webpack-core/lib/RawSource"); var RawSource = require("webpack-core/lib/RawSource");
var ReplaceSource = require("webpack-core/lib/ReplaceSource"); var ReplaceSource = require("webpack-core/lib/ReplaceSource");
var ModuleParseError = require("./ModuleParseError"); var ModuleParseError = require("./ModuleParseError");
var TemplateArgumentDependency = require("./dependencies/TemplateArgumentDependency");
var path = require("path"); var path = require("path");
function NormalModule(request, userRequest, rawRequest, loaders, resource, parser) { function NormalModule(request, userRequest, rawRequest, loaders, resource, parser) {
@ -82,7 +83,7 @@ NormalModule.prototype.source = function(dependencyTemplates, outputOptions, req
function doDep(dep) { function doDep(dep) {
var template = dependencyTemplates.get(dep.Class); var template = dependencyTemplates.get(dep.Class);
if(!template) throw new Error("No template for dependency: " + dep.Class.name); if(!template) throw new Error("No template for dependency: " + dep.Class.name);
template.apply(dep, source, outputOptions, requestShortener); template.apply(dep, source, outputOptions, requestShortener, dependencyTemplates);
} }
function doVariable(vars, variable) { function doVariable(vars, variable) {
var name = variable.name; var name = variable.name;
@ -151,3 +152,82 @@ NormalModule.prototype.updateHash = function(hash) {
hash.update("null"); hash.update("null");
Module.prototype.updateHash.call(this, hash); Module.prototype.updateHash.call(this, hash);
}; };
NormalModule.prototype.getSourceHash = function() {
if(!this._source) return "";
var hash = new (require("crypto").Hash)("md5");
hash.update(this._source.source());
return hash.digest("hex");
};
NormalModule.prototype.getAllModuleDependencies = function() {
var list = [];
function doDep(dep) {
if(dep.module && list.indexOf(dep.module) < 0)
list.push(dep.module);
}
function doVariable(variable) {
variable.dependencies.forEach(doDep);
}
function doBlock(block) {
block.variables.forEach(doVariable);
block.dependencies.forEach(doDep);
block.blocks.forEach(doBlock);
}
doBlock(this);
return list;
};
NormalModule.prototype.createTemplate = function(keepModules) {
var template = new NormalModule("", "", "", [], "", null);
template._source = this._source;
template.built = this.built;
template.templateModules = keepModules;
var args = template.arguments = [];
function doDeps(deps) {
return deps.map(function(dep) {
if(keepModules.indexOf(dep.module) < 0) {
var argName = "__webpack_module_template_argument_" + args.length + "__";
args.push(argName);
return new TemplateArgumentDependency(argName, dep);
} else {
return dep;
}
});
}
function doVariable(variable, newVariable) {
variable.dependencies.forEach(doDep);
}
function doBlock(block, newBlock) {
block.variables.forEach(function(variable) {
var newDependencies = doDeps(variable.dependencies);
newBlock.addVariable(variable.name, variable.expression, newDependencies);
});
newBlock.dependencies = doDeps(block.dependencies);
block.blocks.forEach(function(childBlock) {
var newChildBlock = new AsyncDependenciesBlock(childBlock.name);
newBlock.addBlock(newChildBlock);
doBlock(childBlock, newChildBlock);
});
}
doBlock(this, template);
return template;
};
NormalModule.prototype.getTemplateArguments = function(keepModules) {
var list = [];
function doDep(dep) {
if(dep.module && keepModules.indexOf(dep.module) < 0)
list.push(dep.module);
}
function doVariable(variable) {
variable.dependencies.forEach(doDep);
}
function doBlock(block) {
block.variables.forEach(doVariable);
block.dependencies.forEach(doDep);
block.blocks.forEach(doBlock);
}
doBlock(this);
return list;
};

View File

@ -135,6 +135,7 @@ Stats.prototype.toJson = function toJson(options, forToString) {
userRequest: reason.dependency.userRequest userRequest: reason.dependency.userRequest
} }
var dep = reason.dependency; var dep = reason.dependency;
if(dep.templateModules) obj.templateModules = dep.templateModules.map(function(module) { return module.id; });
if(dep.loc) obj.loc = dep.loc.start.line + ":" + dep.loc.start.column + "-" + if(dep.loc) obj.loc = dep.loc.start.line + ":" + dep.loc.start.column + "-" +
(dep.loc.start.line != dep.loc.end.line ? dep.loc.end.line + ":" : "") + dep.loc.end.column (dep.loc.start.line != dep.loc.end.line ? dep.loc.end.line + ":" : "") + dep.loc.end.column
return obj; return obj;
@ -436,6 +437,7 @@ Stats.jsonToString = function jsonToString(obj, useColors) {
normal(reason.type); normal(reason.type);
normal(" "); normal(" ");
cyan(reason.userRequest); cyan(reason.userRequest);
if(reason.templateModules) cyan(reason.templateModules.join(" "));
normal(" ["); normal(" [");
normal(reason.moduleId); normal(reason.moduleId);
normal("] "); normal("] ");
@ -469,6 +471,7 @@ Stats.jsonToString = function jsonToString(obj, useColors) {
normal(reason.type); normal(reason.type);
normal(" "); normal(" ");
cyan(reason.userRequest); cyan(reason.userRequest);
if(reason.templateModules) cyan(reason.templateModules.join(" "));
normal(" ["); normal(" [");
normal(reason.moduleId); normal(reason.moduleId);
normal("] "); normal("] ");

View File

@ -42,6 +42,7 @@ var RemoveParentModulesPlugin = require("./optimize/RemoveParentModulesPlugin");
var RemoveEmptyChunksPlugin = require("./optimize/RemoveEmptyChunksPlugin"); var RemoveEmptyChunksPlugin = require("./optimize/RemoveEmptyChunksPlugin");
var MergeDuplicateChunksPlugin = require("./optimize/MergeDuplicateChunksPlugin"); var MergeDuplicateChunksPlugin = require("./optimize/MergeDuplicateChunksPlugin");
var FlagIncludedChunksPlugin = require("./optimize/FlagIncludedChunksPlugin"); var FlagIncludedChunksPlugin = require("./optimize/FlagIncludedChunksPlugin");
var DedupePlugin = require("./optimize/DedupePlugin");
var ModulesInDirectoriesPlugin = require("enhanced-resolve/lib/ModulesInDirectoriesPlugin"); var ModulesInDirectoriesPlugin = require("enhanced-resolve/lib/ModulesInDirectoriesPlugin");
var ModulesInRootPlugin = require("enhanced-resolve/lib/ModulesInRootPlugin"); var ModulesInRootPlugin = require("enhanced-resolve/lib/ModulesInRootPlugin");
@ -156,6 +157,9 @@ WebpackOptionsApply.prototype.process = function(options, compiler) {
else if(options.optimize.minimize) else if(options.optimize.minimize)
compiler.apply(new UglifyJsPlugin(options.optimize.minimize)); compiler.apply(new UglifyJsPlugin(options.optimize.minimize));
if(options.optimize.dedupe === true)
compiler.apply(new DedupePlugin());
if(options.cache === undefined ? options.watch : options.cache) if(options.cache === undefined ? options.watch : options.cache)
compiler.apply(new CachePlugin(typeof options.cache == "object" ? options.cache : null)); compiler.apply(new CachePlugin(typeof options.cache == "object" ? options.cache : null));

View File

@ -14,3 +14,7 @@ ModuleDependencyTemplateAsId.prototype.apply = function(dep, source, outputOptio
var content = "(function webpackMissingModule() { throw new Error(" + JSON.stringify("Cannot find module \"" + dep.request + "\"") + "); }())"; var content = "(function webpackMissingModule() { throw new Error(" + JSON.stringify("Cannot find module \"" + dep.request + "\"") + "); }())";
source.replace(dep.range[0], dep.range[1]-1, content); source.replace(dep.range[0], dep.range[1]-1, content);
}; };
ModuleDependencyTemplateAsId.prototype.applyAsTemplateArgument = function(name, dep, source, outputOptions, requestShortener) {
source.replace(dep.range[0], dep.range[1]-1, name);
};

View File

@ -14,3 +14,7 @@ ModuleDependencyTemplateAsRequireId.prototype.apply = function(dep, source, outp
var content = "(function webpackMissingModule() { throw new Error(" + JSON.stringify("Cannot find module \"" + dep.request + "\"") + "); }())"; var content = "(function webpackMissingModule() { throw new Error(" + JSON.stringify("Cannot find module \"" + dep.request + "\"") + "); }())";
source.replace(dep.range[0], dep.range[1]-1, content); source.replace(dep.range[0], dep.range[1]-1, content);
}; };
ModuleDependencyTemplateAsRequireId.prototype.applyAsTemplateArgument = function(name, dep, source, outputOptions, requestShortener) {
source.replace(dep.range[0], dep.range[1]-1, "(require(" + name + "))");
};

View File

@ -0,0 +1,27 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function TemplateArgumentDependency(name, dep) {
this.name = name;
this.Class = TemplateArgumentDependency;
this.dep = dep;
}
module.exports = TemplateArgumentDependency;
TemplateArgumentDependency.prototype.type = "template argument";
TemplateArgumentDependency.prototype.updateHash = function(hash) {
hash.update(this.name);
};
TemplateArgumentDependency.Template = function TemplateArgumentDependencyTemplate() {};
TemplateArgumentDependency.Template.prototype.apply = function(dep, source, outputOptions, requestShortener, dependencyTemplates) {
var d = dep.dep;
var template = dependencyTemplates.get(d.Class);
if(!template) throw new Error("No template for dependency: " + d.Class.name);
if(!template.applyAsTemplateArgument) throw new Error("Template cannot be applied as TemplateArgument: " + d.Class.name);
return template.applyAsTemplateArgument(dep.name, d, source, outputOptions, requestShortener, dependencyTemplates);
};

View File

@ -39,8 +39,9 @@ NodeMainTemplate.prototype.renderRequireEnsure = function(hash, chunk) {
.replace(Template.REGEXP_NAME, "")) .replace(Template.REGEXP_NAME, ""))
.replace(Template.REGEXP_ID, "\" + chunkId + \"") + ");", .replace(Template.REGEXP_ID, "\" + chunkId + \"") + ");",
"var moreModules = chunk.modules, chunkIds = chunk.ids;", "var moreModules = chunk.modules, chunkIds = chunk.ids;",
"for(var moduleId in moreModules)", "for(var moduleId in moreModules) {",
this.indent("modules[moduleId] = moreModules[moduleId];"), this.indent(this.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")),
"}",
"for(var i = 0; i < chunkIds.length; i++)", "for(var i = 0; i < chunkIds.length; i++)",
this.indent("installedChunks[chunkIds[i]] = 1;"), this.indent("installedChunks[chunkIds[i]] = 1;"),
]), ]),

View File

@ -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);
};

View File

@ -50,8 +50,9 @@ WebWorkerMainTemplate.prototype.renderInit = function(hash, chunk) {
buf.push( buf.push(
"this[" + JSON.stringify(chunkCallbackName) + "] = function webpackChunkCallback(chunkIds, moreModules) {", "this[" + JSON.stringify(chunkCallbackName) + "] = function webpackChunkCallback(chunkIds, moreModules) {",
this.indent([ this.indent([
"for(var moduleId in moreModules)", "for(var moduleId in moreModules) {",
this.indent("modules[moduleId] = moreModules[moduleId];"), this.indent(this.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")),
"}",
"while(chunkIds.length)", "while(chunkIds.length)",
this.indent("installedChunks[chunkIds.pop()] = 1;") this.indent("installedChunks[chunkIds.pop()] = 1;")
]), ]),

View File

@ -1,6 +1,6 @@
{ {
"name": "webpack", "name": "webpack",
"version": "0.10.0-beta19", "version": "0.10.0-beta20",
"author": "Tobias Koppers @sokra", "author": "Tobias Koppers @sokra",
"description": "Packs CommonJs/AMD/Labeled Modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jade, coffee, css, less, ... and your custom stuff.", "description": "Packs CommonJs/AMD/Labeled Modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jade, coffee, css, less, ... and your custom stuff.",
"dependencies": { "dependencies": {

View File

@ -34,9 +34,9 @@ var library1 = cp.spawn("node", join(["../../bin/webpack.js", "--output-pathinfo
bindOutput(library1); bindOutput(library1);
library1.on("exit", function(code) { library1.on("exit", function(code) {
if(code === 0) { if(code === 0) {
// node ../../bin/webpack --output-pathinfo --colors --resolve-alias vm=vm-browserify --output-public-path js/ --module-bind json --module-bind css=style!css --module-bind less=style!css!less --module-bind coffee --module-bind jade --prefetch ./less/stylesheet.less ./lib/index js/web.js // node ../../bin/webpack --output-pathinfo --colors --resolve-alias vm=vm-browserify --output-public-path js/ --module-bind json --module-bind css=style!css --module-bind less=style!css!less --module-bind coffee --module-bind jade --prefetch ./less/stylesheet.less --optimize-dedupe ./lib/index js/web.js
var main = cp.spawn("node", join(["../../bin/webpack.js", "--output-pathinfo", "--colors", "--resolve-alias", "vm=vm-browserify", "--workers", var main = cp.spawn("node", join(["../../bin/webpack.js", "--output-pathinfo", "--colors", "--resolve-alias", "vm=vm-browserify", "--workers",
"--output-public-path", "js/", "--module-bind", "json", "--module-bind", "css=style!css", "--module-bind", "less=style/url!file?postfix=.css&string!less", "--module-bind", "coffee", "--module-bind", "jade", "--prefetch", "./less/stylesheet.less", "./lib/index", "js/web.js", "--progress"], extraArgs)); "--output-public-path", "js/", "--module-bind", "json", "--module-bind", "css=style!css", "--module-bind", "less=style/url!file?postfix=.css&string!less", "--module-bind", "coffee", "--module-bind", "jade", "--prefetch", "./less/stylesheet.less", "--optimize-dedupe", "./lib/index", "js/web.js", "--progress"], extraArgs));
bindOutput(main); bindOutput(main);
} }
}); });

View File

@ -0,0 +1 @@
module.exports = "edupe1";

View File

@ -0,0 +1 @@
module.exports = require("../d") + require("./dupdep");

View File

@ -0,0 +1 @@
module.exports = "edupe2";

View File

@ -0,0 +1 @@
module.exports = require("../d") + require("./dupdep");

View File

@ -550,4 +550,13 @@ describe("main", function() {
}); });
}); });
describe("deduplication", function() {
it("should load a duplicate module with different dependencies correctly", function() {
var dedupe1 = require("./dedupe1");
var dedupe2 = require("./dedupe2");
dedupe1.should.be.eql("dedupe1");
dedupe2.should.be.eql("dedupe2");
});
});
}); });