From 44bb43854ffa65d63b84d3db35b7b384cb62c94c Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 11 Jun 2014 22:26:50 +0200 Subject: [PATCH] Added experimental MultiCompiler webpack(...) takes an array support an array in webpack.config.js --- bin/convert-argv.js | 807 +++++++++++++++++++------------------ bin/webpack.js | 4 +- lib/Compiler.js | 1 - lib/MultiCompiler.js | 132 ++++++ lib/Stats.js | 13 +- lib/WebpackOptionsApply.js | 1 + lib/webpack.js | 19 +- 7 files changed, 567 insertions(+), 410 deletions(-) create mode 100644 lib/MultiCompiler.js diff --git a/bin/convert-argv.js b/bin/convert-argv.js index 7e7a96dad..f23bb4bcb 100644 --- a/bin/convert-argv.js +++ b/bin/convert-argv.js @@ -26,100 +26,6 @@ module.exports = function(optimist, argv, convertOptions) { argv["optimize-occurence-order"] = true; } - function ifArg(name, fn, init, finalize) { - if(Array.isArray(argv[name])) { - if(init) { - init(); - } - argv[name].forEach(fn); - if(finalize) { - finalize(); - } - } else if(typeof argv[name] != "undefined") { - if(init) { - init(); - } - fn(argv[name], -1); - if(finalize) { - finalize(); - } - } - } - - function ifArgPair(name, fn, init, finalize) { - ifArg(name, function(content, idx) { - var i = content.indexOf("="); - if(i < 0) { - return fn(null, content, idx); - } else { - return fn(content.substr(0, i), content.substr(i+1), idx); - } - }, init, finalize); - } - - function ifBooleanArg(name, fn) { - ifArg(name, function(bool) { - if(bool) { - fn(); - } - }); - } - - function mapArgToBoolean(name, optionName) { - ifBooleanArg(name, function() { - options[optionName || name] = true; - }); - } - - function mapArgToBooleanInverse(name, optionName) { - ifArg(name, function(bool) { - if(!bool) { - options[optionName || name] = false; - } - }); - } - - function mapArgToPath(name, optionName) { - ifArg(name, function(str) { - options[optionName || name] = path.resolve(str); - }); - } - - function loadPlugin(name) { - var path; - try { - path = resolve.sync(process.cwd(), name); - } catch(e) { - console.log("Cannot resolve plugin " + name + "."); - process.exit(-1); - } - var Plugin; - try { - Plugin = require(path); - } catch(e) { - console.log("Cannot load plugin " + name + ". (" + path + ")"); - throw e; - } - try { - return new Plugin(); - } catch(e) { - console.log("Cannot instantiate plugin " + name + ". (" + path + ")"); - throw e; - } - } - - function ensureObject(parent, name) { - if(typeof parent[name] !== "object" || parent[name] === null) { - parent[name] = {}; - } - } - - function ensureArray(parent, name) { - if(!Array.isArray(parent[name])) { - parent[name] = []; - } - } - if(argv.config) { options = require(path.resolve(argv.config)); } else { @@ -133,323 +39,428 @@ module.exports = function(optimist, argv, convertOptions) { process.exit(-1); } - mapArgToPath("context", "context"); + if(Array.isArray(options)) { + options.forEach(processOptions); + } else { + processOptions(options); + } + + if(argv.context) { + options.context = path.resolve(argv.context) + } if(!options.context) { options.context = process.cwd(); } - ifArgPair("entry", function(name, entry) { - options.entry[name] = entry; - }, function() { - ensureObject(options, "entry"); - }); - - ifArgPair("module-bind", function(name, binding) { - if(name === null) { - name = binding; - } - options.module.loaders.push({ - test: new RegExp("\\." + name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "$"), - loader: binding - }); - }, function() { - ensureObject(options, "module"); - ensureArray(options.module, "loaders"); - }); - - ifArgPair("module-bind-pre", function(name, binding) { - if(name === null) { - name = binding; - } - options.module.preLoaders.push({ - test: new RegExp("\\." + name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "$"), - loader: binding - }); - }, function() { - ensureObject(options, "module"); - ensureArray(options.module, "preLoaders"); - }); - - ifArgPair("module-bind-post", function(name, binding) { - if(name === null) { - name = binding; - } - options.module.postLoaders.push({ - test: new RegExp("\\." + name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "$"), - loader: binding - }); - }, function() { - ensureObject(options, "module"); - ensureArray(options.module, "postLoaders"); - }); - - var defineObject; - ifArgPair("define", function(name, value) { - if(name === null) { - name = value; - value = true; - } - defineObject[name] = value; - }, function() { - defineObject = {}; - }, function() { - ensureArray(options, "plugins"); - var DefinePlugin = require("../lib/DefinePlugin"); - options.plugins.push(new DefinePlugin(defineObject)); - }); - - ifArg("output-path", function(value) { - ensureObject(options, "output"); - options.output.path = value; - }); - - ifArg("output-file", function(value) { - ensureObject(options, "output"); - options.output.filename = value; - }); - - ifArg("output-chunk-file", function(value) { - ensureObject(options, "output"); - options.output.chunkFilename = value; - }); - - ifArg("output-named-chunk-file", function(value) { - ensureObject(options, "output"); - options.output.namedChunkFilename = value; - }); - - ifArg("output-source-map-file", function(value) { - ensureObject(options, "output"); - options.output.sourceMapFilename = value; - }); - - ifArg("output-public-path", function(value) { - ensureObject(options, "output"); - options.output.publicPath = value; - }); - - ifArg("output-jsonp-function", function(value) { - ensureObject(options, "output"); - options.output.jsonpFunction = value; - }); - - ifBooleanArg("output-pathinfo", function() { - ensureObject(options, "output"); - options.output.pathinfo = true; - }); - - ifArg("output-library", function(value) { - ensureObject(options, "output"); - options.output.library = value; - }); - - ifArg("output-library-target", function(value) { - ensureObject(options, "output"); - options.output.libraryTarget = value; - }); - - ifArg("records-input-path", function(value) { - options.recordsInputPath = path.resolve(value); - }); - - ifArg("records-output-path", function(value) { - options.recordsOutputPath = path.resolve(value); - }); - - ifArg("records-path", function(value) { - options.recordsPath = path.resolve(value); - }); - - ifArg("target", function(value) { - options.target = value; - }); - - mapArgToBooleanInverse("cache"); - mapArgToBoolean("watch"); - - ifArg("watch-delay", function(value) { - options.watchDelay = value; - }); - - ifBooleanArg("hot", function() { - ensureArray(options, "plugins"); - var HotModuleReplacementPlugin = require("../lib/HotModuleReplacementPlugin"); - options.plugins.push(new HotModuleReplacementPlugin()); - }); - - mapArgToBoolean("debug"); - - ifBooleanArg("progress", function() { - var ProgressPlugin = require("../lib/ProgressPlugin"); - ensureArray(options, "plugins"); - var chars = 0, lastState, lastStateTime; - options.plugins.push(new ProgressPlugin(function(percentage, msg) { - var state = msg; - if(percentage < 1) { - percentage = Math.floor(percentage * 100); - msg = percentage + "% " + msg; - if(percentage < 100) { - msg = " " + msg; + function processOptions(options) { + function ifArg(name, fn, init, finalize) { + if(Array.isArray(argv[name])) { + if(init) { + init(); } - if(percentage < 10) { - msg = " " + msg; + argv[name].forEach(fn); + if(finalize) { + finalize(); + } + } else if(typeof argv[name] != "undefined") { + if(init) { + init(); + } + fn(argv[name], -1); + if(finalize) { + finalize(); } } - for(; chars > msg.length; chars--) { - process.stderr.write("\b \b"); - } - chars = msg.length; - for(var i = 0; i < chars; i++) { - process.stderr.write("\b"); - } - if(options.profile) { - state = state.replace(/^\d+\/\d+\s+/, ""); - if(percentage === 0) { - lastState = null; - lastStateTime = +new Date(); - } else if(state !== lastState || percentage === 1) { - var now = +new Date(); - if(lastState) { - process.stderr.write((now - lastStateTime) + "ms " + lastState + "\n"); - } - lastState = state; - lastStateTime = now; - } - } - process.stderr.write(msg); - })); - }); - - ifArg("devtool", function(value) { - options.devtool = value; - }); - - ifArgPair("resolve-alias", function(name, value) { - if(!name) { - throw new Error("--resolve-alias ="); } - ensureObject(options, "resolve"); - ensureObject(options.resolve, "alias"); - options.resolve.alias[name] = value; - }); - ifArgPair("resolve-loader-alias", function(name, value) { - if(!name) { - throw new Error("--resolve-loader-alias ="); - } - ensureObject(options, "resolveLoader"); - ensureObject(options.resolveLoader, "alias"); - options.resolveLoader.alias[name] = value; - }); - - ifArg("optimize-max-chunks", function(value) { - ensureArray(options, "plugins"); - var LimitChunkCountPlugin = require("../lib/optimize/LimitChunkCountPlugin"); - options.plugins.push(new LimitChunkCountPlugin({ - maxChunks: parseInt(value, 10) - })); - }); - - ifArg("optimize-min-chunk-size", function(value) { - ensureArray(options, "plugins"); - var LimitChunkSizePlugin = require("../lib/optimize/LimitChunkSizePlugin"); - options.plugins.push(new LimitChunkSizePlugin(parseInt(value, 10))); - }); - - ifBooleanArg("optimize-minimize", function() { - ensureArray(options, "plugins"); - var UglifyJsPlugin = require("../lib/optimize/UglifyJsPlugin"); - options.plugins.push(new UglifyJsPlugin()); - }); - - ifBooleanArg("optimize-occurence-order", function() { - ensureArray(options, "plugins"); - var OccurenceOrderPlugin = require("../lib/optimize/OccurenceOrderPlugin"); - options.plugins.push(new OccurenceOrderPlugin()); - }); - - ifBooleanArg("optimize-dedupe", function() { - ensureArray(options, "plugins"); - var DedupePlugin = require("../lib/optimize/DedupePlugin"); - options.plugins.push(new DedupePlugin()); - }); - - ifArg("prefetch", function(request) { - ensureArray(options, "plugins"); - var PrefetchPlugin = require("../lib/PrefetchPlugin"); - options.plugins.push(new PrefetchPlugin(request)); - }); - - ifArg("provide", function(value) { - ensureArray(options, "plugins"); - var idx = value.indexOf("="); - var name; - if(idx >= 0) { - name = value.substr(0, idx); - value = value.substr(idx + 1); - } else { - name = value; - } - var ProvidePlugin = require("../lib/ProvidePlugin"); - options.plugins.push(new ProvidePlugin(name, value)); - }); - - ifBooleanArg("labeled-modules", function() { - ensureArray(options, "plugins"); - var LabeledModulesPlugin = require("../lib/dependencies/LabeledModulesPlugin"); - options.plugins.push(new LabeledModulesPlugin()); - }); - - ifArg("plugin", function(value) { - ensureArray(options, "plugins"); - options.plugins.push(loadPlugin(value)); - }); - - mapArgToBoolean("bail"); - - mapArgToBoolean("profile"); - - if(!options.output || !options.output.filename) { - ensureObject(options, "output"); - if(convertOptions && convertOptions.outputFilename) { - options.output.path = path.dirname(convertOptions.outputFilename); - options.output.filename = path.basename(convertOptions.outputFilename); - } else if(argv._.length > 0) { - options.output.filename = argv._.pop(); - options.output.path = path.dirname(options.output.filename); - options.output.filename = path.basename(options.output.filename); - } else { - optimist.showHelp(); - process.exit(-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("="); - var j = content.indexOf("?"); - if(i < 0 || (j >= 0 && j < i)) { - var resolved = path.resolve(content); - if(fs.existsSync(resolved)) { - addTo("main", resolved); + function ifArgPair(name, fn, init, finalize) { + ifArg(name, function(content, idx) { + var i = content.indexOf("="); + if(i < 0) { + return fn(null, content, idx); } else { - addTo("main", content); + return fn(content.substr(0, i), content.substr(i+1), idx); } - } else { - addTo(content.substr(0, i), content.substr(i+1)); + }, init, finalize); + } + + function ifBooleanArg(name, fn) { + ifArg(name, function(bool) { + if(bool) { + fn(); + } + }); + } + + function mapArgToBoolean(name, optionName) { + ifBooleanArg(name, function() { + options[optionName || name] = true; + }); + } + + function mapArgToBooleanInverse(name, optionName) { + ifArg(name, function(bool) { + if(!bool) { + options[optionName || name] = false; + } + }); + } + + function mapArgToPath(name, optionName) { + ifArg(name, function(str) { + options[optionName || name] = path.resolve(str); + }); + } + + function loadPlugin(name) { + var path; + try { + path = resolve.sync(process.cwd(), name); + } catch(e) { + console.log("Cannot resolve plugin " + name + "."); + process.exit(-1); } + var Plugin; + try { + Plugin = require(path); + } catch(e) { + console.log("Cannot load plugin " + name + ". (" + path + ")"); + throw e; + } + try { + return new Plugin(); + } catch(e) { + console.log("Cannot instantiate plugin " + name + ". (" + path + ")"); + throw e; + } + } + + function ensureObject(parent, name) { + if(typeof parent[name] !== "object" || parent[name] === null) { + parent[name] = {}; + } + } + + function ensureArray(parent, name) { + if(!Array.isArray(parent[name])) { + parent[name] = []; + } + } + + ifArgPair("entry", function(name, entry) { + options.entry[name] = entry; + }, function() { + ensureObject(options, "entry"); }); + + ifArgPair("module-bind", function(name, binding) { + if(name === null) { + name = binding; + } + options.module.loaders.push({ + test: new RegExp("\\." + name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "$"), + loader: binding + }); + }, function() { + ensureObject(options, "module"); + ensureArray(options.module, "loaders"); + }); + + ifArgPair("module-bind-pre", function(name, binding) { + if(name === null) { + name = binding; + } + options.module.preLoaders.push({ + test: new RegExp("\\." + name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "$"), + loader: binding + }); + }, function() { + ensureObject(options, "module"); + ensureArray(options.module, "preLoaders"); + }); + + ifArgPair("module-bind-post", function(name, binding) { + if(name === null) { + name = binding; + } + options.module.postLoaders.push({ + test: new RegExp("\\." + name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "$"), + loader: binding + }); + }, function() { + ensureObject(options, "module"); + ensureArray(options.module, "postLoaders"); + }); + + var defineObject; + ifArgPair("define", function(name, value) { + if(name === null) { + name = value; + value = true; + } + defineObject[name] = value; + }, function() { + defineObject = {}; + }, function() { + ensureArray(options, "plugins"); + var DefinePlugin = require("../lib/DefinePlugin"); + options.plugins.push(new DefinePlugin(defineObject)); + }); + + ifArg("output-path", function(value) { + ensureObject(options, "output"); + options.output.path = value; + }); + + ifArg("output-file", function(value) { + ensureObject(options, "output"); + options.output.filename = value; + }); + + ifArg("output-chunk-file", function(value) { + ensureObject(options, "output"); + options.output.chunkFilename = value; + }); + + ifArg("output-named-chunk-file", function(value) { + ensureObject(options, "output"); + options.output.namedChunkFilename = value; + }); + + ifArg("output-source-map-file", function(value) { + ensureObject(options, "output"); + options.output.sourceMapFilename = value; + }); + + ifArg("output-public-path", function(value) { + ensureObject(options, "output"); + options.output.publicPath = value; + }); + + ifArg("output-jsonp-function", function(value) { + ensureObject(options, "output"); + options.output.jsonpFunction = value; + }); + + ifBooleanArg("output-pathinfo", function() { + ensureObject(options, "output"); + options.output.pathinfo = true; + }); + + ifArg("output-library", function(value) { + ensureObject(options, "output"); + options.output.library = value; + }); + + ifArg("output-library-target", function(value) { + ensureObject(options, "output"); + options.output.libraryTarget = value; + }); + + ifArg("records-input-path", function(value) { + options.recordsInputPath = path.resolve(value); + }); + + ifArg("records-output-path", function(value) { + options.recordsOutputPath = path.resolve(value); + }); + + ifArg("records-path", function(value) { + options.recordsPath = path.resolve(value); + }); + + ifArg("target", function(value) { + options.target = value; + }); + + mapArgToBooleanInverse("cache"); + mapArgToBoolean("watch"); + + ifArg("watch-delay", function(value) { + options.watchDelay = value; + }); + + ifBooleanArg("hot", function() { + ensureArray(options, "plugins"); + var HotModuleReplacementPlugin = require("../lib/HotModuleReplacementPlugin"); + options.plugins.push(new HotModuleReplacementPlugin()); + }); + + mapArgToBoolean("debug"); + + ifBooleanArg("progress", function() { + var ProgressPlugin = require("../lib/ProgressPlugin"); + ensureArray(options, "plugins"); + var chars = 0, lastState, lastStateTime; + options.plugins.push(new ProgressPlugin(function(percentage, msg) { + var state = msg; + if(percentage < 1) { + percentage = Math.floor(percentage * 100); + msg = percentage + "% " + msg; + if(percentage < 100) { + msg = " " + msg; + } + if(percentage < 10) { + msg = " " + msg; + } + } + for(; chars > msg.length; chars--) { + process.stderr.write("\b \b"); + } + chars = msg.length; + for(var i = 0; i < chars; i++) { + process.stderr.write("\b"); + } + if(options.profile) { + state = state.replace(/^\d+\/\d+\s+/, ""); + if(percentage === 0) { + lastState = null; + lastStateTime = +new Date(); + } else if(state !== lastState || percentage === 1) { + var now = +new Date(); + if(lastState) { + process.stderr.write((now - lastStateTime) + "ms " + lastState + "\n"); + } + lastState = state; + lastStateTime = now; + } + } + process.stderr.write(msg); + })); + }); + + ifArg("devtool", function(value) { + options.devtool = value; + }); + + ifArgPair("resolve-alias", function(name, value) { + if(!name) { + throw new Error("--resolve-alias ="); + } + ensureObject(options, "resolve"); + ensureObject(options.resolve, "alias"); + options.resolve.alias[name] = value; + }); + + ifArgPair("resolve-loader-alias", function(name, value) { + if(!name) { + throw new Error("--resolve-loader-alias ="); + } + ensureObject(options, "resolveLoader"); + ensureObject(options.resolveLoader, "alias"); + options.resolveLoader.alias[name] = value; + }); + + ifArg("optimize-max-chunks", function(value) { + ensureArray(options, "plugins"); + var LimitChunkCountPlugin = require("../lib/optimize/LimitChunkCountPlugin"); + options.plugins.push(new LimitChunkCountPlugin({ + maxChunks: parseInt(value, 10) + })); + }); + + ifArg("optimize-min-chunk-size", function(value) { + ensureArray(options, "plugins"); + var LimitChunkSizePlugin = require("../lib/optimize/LimitChunkSizePlugin"); + options.plugins.push(new LimitChunkSizePlugin(parseInt(value, 10))); + }); + + ifBooleanArg("optimize-minimize", function() { + ensureArray(options, "plugins"); + var UglifyJsPlugin = require("../lib/optimize/UglifyJsPlugin"); + options.plugins.push(new UglifyJsPlugin()); + }); + + ifBooleanArg("optimize-occurence-order", function() { + ensureArray(options, "plugins"); + var OccurenceOrderPlugin = require("../lib/optimize/OccurenceOrderPlugin"); + options.plugins.push(new OccurenceOrderPlugin()); + }); + + ifBooleanArg("optimize-dedupe", function() { + ensureArray(options, "plugins"); + var DedupePlugin = require("../lib/optimize/DedupePlugin"); + options.plugins.push(new DedupePlugin()); + }); + + ifArg("prefetch", function(request) { + ensureArray(options, "plugins"); + var PrefetchPlugin = require("../lib/PrefetchPlugin"); + options.plugins.push(new PrefetchPlugin(request)); + }); + + ifArg("provide", function(value) { + ensureArray(options, "plugins"); + var idx = value.indexOf("="); + var name; + if(idx >= 0) { + name = value.substr(0, idx); + value = value.substr(idx + 1); + } else { + name = value; + } + var ProvidePlugin = require("../lib/ProvidePlugin"); + options.plugins.push(new ProvidePlugin(name, value)); + }); + + ifBooleanArg("labeled-modules", function() { + ensureArray(options, "plugins"); + var LabeledModulesPlugin = require("../lib/dependencies/LabeledModulesPlugin"); + options.plugins.push(new LabeledModulesPlugin()); + }); + + ifArg("plugin", function(value) { + ensureArray(options, "plugins"); + options.plugins.push(loadPlugin(value)); + }); + + mapArgToBoolean("bail"); + + mapArgToBoolean("profile"); + + if(!options.output || !options.output.filename) { + ensureObject(options, "output"); + if(convertOptions && convertOptions.outputFilename) { + options.output.path = path.dirname(convertOptions.outputFilename); + options.output.filename = path.basename(convertOptions.outputFilename); + } else if(argv._.length > 0) { + options.output.filename = argv._.pop(); + options.output.path = path.dirname(options.output.filename); + options.output.filename = path.basename(options.output.filename); + } else { + optimist.showHelp(); + process.exit(-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("="); + var j = content.indexOf("?"); + if(i < 0 || (j >= 0 && j < i)) { + var resolved = path.resolve(content); + if(fs.existsSync(resolved)) { + addTo("main", resolved); + } else { + addTo("main", content); + } + } else { + addTo(content.substr(0, i), content.substr(i+1)); + } + }); + } + } return options; diff --git a/bin/webpack.js b/bin/webpack.js index 4e7b849f5..ade542dd1 100644 --- a/bin/webpack.js +++ b/bin/webpack.js @@ -145,8 +145,8 @@ var compiler = webpack(options, function(err, stats) { } if(outputOptions.json) { process.stdout.write(JSON.stringify(stats.toJson(outputOptions), null, 2) + "\n"); - } else if(stats.compilation.hash !== lastHash) { - lastHash = stats.compilation.hash; + } else if(stats.hash !== lastHash) { + lastHash = stats.hash; process.stdout.write(stats.toString(outputOptions) + "\n"); } }); \ No newline at end of file diff --git a/lib/Compiler.js b/lib/Compiler.js index b2100a515..feb9e27a3 100644 --- a/lib/Compiler.js +++ b/lib/Compiler.js @@ -126,7 +126,6 @@ function Compiler() { this.outputPath = ""; this.outputFileSystem = null; this.inputFileSystem = null; - this.separateExecutor = null; this.recordsInputPath = null; this.recordsOutputPath = null; diff --git a/lib/MultiCompiler.js b/lib/MultiCompiler.js new file mode 100644 index 000000000..011a762e8 --- /dev/null +++ b/lib/MultiCompiler.js @@ -0,0 +1,132 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +var Tapable = require("tapable"); +var async = require("async"); +var Stats = require("./Stats"); + +function MultiWatching(watchings) { + this.watchings = watchings; +} + +MultiWatching.prototype.invalidate = function() { + this.watchings.forEach(function(watching) { + watching.invalidate(); + }); +}; + +MultiWatching.prototype.close = function(callback) { + async.forEach(this.watchings, function(watching, callback) { + watching.close(callback); + }, callback); +}; + +function MultiCompiler(compilers) { + Tapable.call(this); + if(!Array.isArray(compilers)) { + compilers = Object.keys(compilers).map(function(name) { + compilers[name].name = name; + return compilers[name]; + }); + } + this.compilers = compilers; + + function delegateProperty(name) { + Object.defineProperty(this, name, { + configurable: false, + get: function() { + throw new Error("Cannot read " + name + " of a MultiCompiler"); + }, + set: function(value) { + this.compilers.forEach(function(compiler) { + compiler[name] = value; + }); + }.bind(this) + }); + } + delegateProperty.call(this, "outputFileSystem"); + delegateProperty.call(this, "inputFileSystem"); + + var doneCompilers = 0; + var compilerStats = []; + this.compilers.forEach(function(compiler, idx) { + var compilerDone = false; + compiler.plugin("done", function(stats) { + if(!compilerDone) { + compilerDone = true; + doneCompilers++; + } + compilerStats[idx] = stats; + if(doneCompilers === this.compilers.length) { + this.applyPlugins("done", new MultiStats(compilerStats)); + } + }.bind(this)); + compiler.plugin("invalid", function() { + this.applyPlugins("invalid"); + }); + }, this); +} +module.exports = MultiCompiler; + +MultiCompiler.prototype = Object.create(Tapable.prototype); + +MultiCompiler.prototype.watch = function(watchDelay, handler) { + var watchings = this.compilers.map(function(compiler) { + return compiler.watch(watchDelay, handler); + }); + return new MultiWatching(watchings); +}; + +MultiCompiler.prototype.run = function(callback) { + async.map(this.compilers, function(compiler, callback) { + compiler.run(callback); + }, function(err, stats) { + if(err) return callback(err); + callback(null, new MultiStats(stats)); + }); +}; + +function MultiStats(stats) { + this.stats = stats; + this.hash = stats.map(function(stat) { + return stat.hash; + }).join(""); +} + +MultiStats.prototype.hasErrors = function() { + return this.stats.map(function(stat) { + return stat.hasErrors(); + }).reduce(function(a, b) { return a || b; }, false); +}; + +MultiStats.prototype.hasWarnings = function() { + return this.stats.map(function(stat) { + return stat.hasWarnings(); + }).reduce(function(a, b) { return a || b; }, false); +}; + +MultiStats.prototype.toJson = function(options, forToString) { + var jsons = this.stats.map(function(stat) { + var obj = stat.toJson(options, forToString); + obj.name = stat.compilation && stat.compilation.name; + return obj; + }); + return { + version: require("../package.json").version, + hash: this.hash, + errors: jsons.reduce(function(arr, j) { + return arr.concat(j.errors.map(function(msg) { + return "(" + j.name + ") " + msg + })); + }, []), + warnings: jsons.reduce(function(arr, j) { + return arr.concat(j.warnings.map(function(msg) { + return "(" + j.name + ") " + msg + })); + }, []), + children: jsons + }; +}; + +MultiStats.prototype.toString = Stats.prototype.toString; \ No newline at end of file diff --git a/lib/Stats.js b/lib/Stats.js index 8eab6c559..8da0502dd 100644 --- a/lib/Stats.js +++ b/lib/Stats.js @@ -6,6 +6,7 @@ var RequestShortener = require("./RequestShortener"); function Stats(compilation) { this.compilation = compilation; + this.hash = compilation.hash; } module.exports = Stats; @@ -79,7 +80,7 @@ Stats.prototype.toJson = function toJson(options, forToString) { warnings: compilation.warnings.map(formatError) }; - if(showHash) obj.hash = compilation.hash; + if(showHash) obj.hash = this.hash; if(showTimings && this.startTime && this.endTime) { obj.time = this.endTime - this.startTime; } @@ -557,9 +558,13 @@ Stats.jsonToString = function jsonToString(obj, useColors) { } if(obj.children) { obj.children.forEach(function(child) { - normal("Child "); - bold(child.name); - normal(":"); + if(child.name) { + normal("Child "); + bold(child.name); + normal(":"); + } else { + normal("Child"); + } newline(); buf.push(" "); buf.push(Stats.jsonToString(child, useColors).replace(/\n/g, "\n ")); diff --git a/lib/WebpackOptionsApply.js b/lib/WebpackOptionsApply.js index 7a43ab653..03ced9ffc 100644 --- a/lib/WebpackOptionsApply.js +++ b/lib/WebpackOptionsApply.js @@ -65,6 +65,7 @@ WebpackOptionsApply.prototype.process = function(options, compiler) { compiler.outputPath = options.output.path; compiler.recordsInputPath = options.recordsInputPath || options.recordsPath; compiler.recordsOutputPath = options.recordsOutputPath || options.recordsPath; + compiler.name = options.name; if(typeof options.target === "string") { switch(options.target) { case "web": diff --git a/lib/webpack.js b/lib/webpack.js index 12ac651f0..4868e242d 100644 --- a/lib/webpack.js +++ b/lib/webpack.js @@ -3,17 +3,25 @@ Author Tobias Koppers @sokra */ var Compiler = require("./Compiler"); +var MultiCompiler = require("./MultiCompiler"); var NodeEnvironmentPlugin = require("./node/NodeEnvironmentPlugin"); var WebpackOptionsApply = require("./WebpackOptionsApply"); var WebpackOptionsDefaulter = require("./WebpackOptionsDefaulter"); function webpack(options, callback) { - new WebpackOptionsDefaulter().process(options); + var compiler; + if(Array.isArray(options)) { + compiler = new MultiCompiler(options.map(function(options) { + return webpack(options); + })); + } else { + new WebpackOptionsDefaulter().process(options); - var compiler = new Compiler(); - compiler.options = options; - compiler.options = new WebpackOptionsApply().process(options, compiler); - new NodeEnvironmentPlugin().apply(compiler); + compiler = new Compiler(); + compiler.options = options; + compiler.options = new WebpackOptionsApply().process(options, compiler); + new NodeEnvironmentPlugin().apply(compiler); + } if(callback) { if(options.watch) { return compiler.watch(options.watchDelay, callback); @@ -28,6 +36,7 @@ exports = module.exports = webpack; webpack.WebpackOptionsDefaulter = WebpackOptionsDefaulter; webpack.WebpackOptionsApply = WebpackOptionsApply; webpack.Compiler = Compiler; +webpack.MultiCompiler = MultiCompiler; webpack.NodeEnvironmentPlugin = NodeEnvironmentPlugin; function exportPlugins(exports, path, plugins) {