From 55d1af81093c48beeb85a5dbb9c702172c6df720 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 31 Jan 2013 01:44:39 +0100 Subject: [PATCH] fix named chunks, added multi entry plugin --- bin/convert-argv.js | 17 ++++-- lib/Compilation.js | 2 +- lib/MultiEntryPlugin.js | 29 +++++++++ lib/MultiModule.js | 69 ++++++++++++++++++++++ lib/MultiModuleFactory.js | 18 ++++++ lib/WebpackOptionsApply.js | 13 +++- lib/dependencies/MultiEntryDependency.js | 16 +++++ test/browsertest/build.js | 4 +- test/browsertest/lib/index.web.js | 19 ++++++ test/browsertest/node_modules/library2b.js | 5 ++ 10 files changed, 181 insertions(+), 11 deletions(-) create mode 100644 lib/MultiEntryPlugin.js create mode 100644 lib/MultiModule.js create mode 100644 lib/MultiModuleFactory.js create mode 100644 lib/dependencies/MultiEntryDependency.js create mode 100644 test/browsertest/node_modules/library2b.js diff --git a/bin/convert-argv.js b/bin/convert-argv.js index 4b9b20783..53ae4adda 100644 --- a/bin/convert-argv.js +++ b/bin/convert-argv.js @@ -241,15 +241,22 @@ module.exports = function(optimist, argv, convertOptions) { } } - if(argv._.length > 1) { + if(argv._.length > 0) { ensureObject(options, "entry"); + function addTo(name, entry) { + if(options.entry[name]) { + if(!Array.isArray(options.entry[name])) + options.entry[name] = [options.entry[name]]; + options.entry[name].push(entry); + } else { + options.entry[name] = entry; + } + } argv._.forEach(function(content) { var i = content.indexOf("="); - if(i < 0) throw new Error("Each element must be =."); - else return options.entry[content.substr(0, i)] = content.substr(i+1); + if(i < 0) addTo("main", content); + else addTo(content.substr(0, i), content.substr(i+1)) }); - } else if(argv._.length == 1) { - options.entry = argv._[0]; } return options; diff --git a/lib/Compilation.js b/lib/Compilation.js index c7e5d81be..731c0d041 100644 --- a/lib/Compilation.js +++ b/lib/Compilation.js @@ -267,7 +267,7 @@ Compilation.prototype.seal = function seal(callback) { Compilation.prototype.addChunk = function addChunk(name) { if(name) { - if(Object.prototype.hasOwnProperty(this.namedChunks, name)) + if(Object.prototype.hasOwnProperty.call(this.namedChunks, name)) return this.namedChunks[name]; } var chunk = new Chunk(name); diff --git a/lib/MultiEntryPlugin.js b/lib/MultiEntryPlugin.js new file mode 100644 index 000000000..c5e706c54 --- /dev/null +++ b/lib/MultiEntryPlugin.js @@ -0,0 +1,29 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var MultiEntryDependency = require("./dependencies/MultiEntryDependency"); +var SingleEntryDependency = require("./dependencies/SingleEntryDependency"); +var MultiModuleFactory = require("./MultiModuleFactory"); + +function MultiEntryPlugin(context, entries, name) { + this.context = context; + this.entries = entries; + this.name = name; +} +module.exports = MultiEntryPlugin; +MultiEntryPlugin.prototype.apply = function(compiler) { + compiler.plugin("compilation", function(compilation, params) { + var multiModuleFactory = new MultiModuleFactory(); + var normalModuleFactory = params.normalModuleFactory; + + compilation.dependencyFactories.set(MultiEntryDependency, multiModuleFactory); + + compilation.dependencyFactories.set(SingleEntryDependency, normalModuleFactory); + }); + compiler.plugin("make", function(compilation, callback) { + compilation.addEntry(this.context, new MultiEntryDependency(this.entries.map(function(e) { + return new SingleEntryDependency(e); + }), this.name), this.name, callback); + }.bind(this)); +}; \ No newline at end of file diff --git a/lib/MultiModule.js b/lib/MultiModule.js new file mode 100644 index 000000000..1f7867976 --- /dev/null +++ b/lib/MultiModule.js @@ -0,0 +1,69 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var Module = require("./Module"); +var RawSource = require("webpack-core/lib/RawSource"); + +function MultiModule(context, dependencies, name) { + Module.call(this); + this.context = context; + this.dependencies = dependencies; + this.name = name; + this.built = false; + this.cacheable = true; +} +module.exports = MultiModule; + +MultiModule.prototype = Object.create(Module.prototype); + +MultiModule.prototype.identifier = function() { + return "multi " + this.name; +}; + +MultiModule.prototype.readableIdentifier = function(requestShortener) { + return "multi " + this.name; +}; + +MultiModule.prototype.disconnect = function disconnect() { + this.built = false; + Module.prototype.disconnect.call(this); +}; + +MultiModule.prototype.build = function build(options, compilation, resolver, fs, callback) { + this.built = true; + return callback(); +}; + +MultiModule.prototype.source = function(dependencyTemplates, outputOptions, requestShortener) { + var str = ["module.exports = "]; + this.dependencies.forEach(function(dep, idx) { + if(dep.module) { + str.push("require("); + if(outputOptions.pathinfo) + str.push("/*! "+dep.request+" */"); + str.push(""+dep.module.id); + str.push(")"); + } else { + str.push("(function webpackMissingModule() { throw new Error("); + str.push(JSON.stringify("Cannot find module \"" + dep.request + "\"")); + str.push("); }())"); + } + str.push(";\n"); + }); + return new RawSource(str.join("")); +}; + +MultiModule.prototype.needRebuild = function needRebuild(fileTimestamps, contextTimestamps) { + return false; +}; + +MultiModule.prototype.size = function() { + return 16 + this.dependencies.length * 12; +}; + +MultiModule.prototype.updateHash = function(hash) { + hash.update("multi module"); + hash.update(this.name || ""); + Module.prototype.updateHash.call(this, hash); +}; diff --git a/lib/MultiModuleFactory.js b/lib/MultiModuleFactory.js new file mode 100644 index 000000000..09d4afa36 --- /dev/null +++ b/lib/MultiModuleFactory.js @@ -0,0 +1,18 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var async = require("async"); + +var Tapable = require("tapable"); +var MultiModule = require("./MultiModule"); + +function MultiModuleFactory() { + Tapable.call(this); +} +module.exports = MultiModuleFactory; + +MultiModuleFactory.prototype = Object.create(Tapable.prototype); +MultiModuleFactory.prototype.create = function(context, dependency, callback) { + callback(null, new MultiModule(context, dependency.dependencies, dependency.name)); +}; diff --git a/lib/WebpackOptionsApply.js b/lib/WebpackOptionsApply.js index 4ebc91b57..50213f8dd 100644 --- a/lib/WebpackOptionsApply.js +++ b/lib/WebpackOptionsApply.js @@ -10,6 +10,7 @@ var EvalDevToolModulePlugin = require("./EvalDevToolModulePlugin"); var LibraryTemplatePlugin = require("./LibraryTemplatePlugin"); var SingleEntryPlugin = require("./SingleEntryPlugin"); +var MultiEntryPlugin = require("./MultiEntryPlugin"); var CachePlugin = require("./CachePlugin"); var UglifyJsPlugin = require("./UglifyJsPlugin"); @@ -59,11 +60,17 @@ WebpackOptionsApply.prototype.process = function(options, compiler) { compiler.apply(new LibraryTemplatePlugin(options.output.library, options.output.libraryTarget)); if(options.devtool == "eval") compiler.apply(new EvalDevToolModulePlugin()); - if(typeof options.entry == "string") { - compiler.apply(new SingleEntryPlugin(options.context, options.entry, "main")); + function itemToPlugin(item, name) { + if(Array.isArray(item)) + return new MultiEntryPlugin(options.context, item, name); + else + return new SingleEntryPlugin(options.context, item, name) + } + if(typeof options.entry == "string" || Array.isArray(options.entry)) { + compiler.apply(itemToPlugin(options.entry, "main")); } else if(typeof options.entry == "object") { Object.keys(options.entry).forEach(function(name) { - compiler.apply(new SingleEntryPlugin(options.context, options.entry[name], name)); + compiler.apply(itemToPlugin(options.entry[name], name)); }); } compiler.apply( diff --git a/lib/dependencies/MultiEntryDependency.js b/lib/dependencies/MultiEntryDependency.js new file mode 100644 index 000000000..87ce9bcec --- /dev/null +++ b/lib/dependencies/MultiEntryDependency.js @@ -0,0 +1,16 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var Dependency = require("../Dependency"); + +function MultiEntryDependency(dependencies, name) { + Dependency.call(this); + this.Class = MultiEntryDependency; + this.dependencies = dependencies; + this.name = name; +} +module.exports = MultiEntryDependency; + +MultiEntryDependency.prototype = Object.create(Dependency.prototype); +MultiEntryDependency.prototype.type = "multi entry"; diff --git a/test/browsertest/build.js b/test/browsertest/build.js index 4e3f12090..0965c4266 100644 --- a/test/browsertest/build.js +++ b/test/browsertest/build.js @@ -40,7 +40,7 @@ library1.on("exit", function(code) { bindOutput(main); } }); -// node ../../bin/webpack --output-pathinfo --colors --output-library library2 --output-public-path js/ --config library2config.js library2 js/library2.js +// node ../../bin/webpack --output-pathinfo --colors --output-library library2 --output-public-path js/ --config library2config.js library2 library2b js/library2.js var library2 = cp.spawn("node", join(["../../bin/webpack.js", "--output-pathinfo", "--colors", "--output-library", "library2", - "--output-public-path", "js/", "--config", "library2config.js", "library2", "js/library2.js"], extraArgsNoWatch)); + "--output-public-path", "js/", "--config", "library2config.js", "library2", "library2b", "js/library2.js"], extraArgsNoWatch)); bindOutput(library2); diff --git a/test/browsertest/lib/index.web.js b/test/browsertest/lib/index.web.js index 0ca2fb35d..65cb47d8a 100644 --- a/test/browsertest/lib/index.web.js +++ b/test/browsertest/lib/index.web.js @@ -240,6 +240,25 @@ describe("main", function() { if(firstOne) done(); }); }); + + it("should handle named chunks", function(done) { + var sync = false; + require.ensure([], function(require) { + require("./empty?a"); + require("./empty?b"); + sync = true; + testLoad(); + sync = false; + done(); + }, "named-chunk"); + function testLoad() { + require.ensure([], function(require) { + require("./empty?c"); + require("./empty?d"); + sync.should.be.ok; + }, "named-chunk"); + } + }); }); describe("loaders", function() { diff --git a/test/browsertest/node_modules/library2b.js b/test/browsertest/node_modules/library2b.js new file mode 100644 index 000000000..56f800447 --- /dev/null +++ b/test/browsertest/node_modules/library2b.js @@ -0,0 +1,5 @@ +describe("library2b", function() { + it("should load this library", function() { + true.should.be.ok; + }); +});