| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | var Tapable = require("tapable"); | 
					
						
							| 
									
										
										
										
											2017-04-05 21:06:23 +08:00
										 |  |  | var asyncLib = require("async"); | 
					
						
							| 
									
										
										
										
											2017-01-07 14:56:47 +08:00
										 |  |  | var MultiWatching = require("./MultiWatching"); | 
					
						
							|  |  |  | var MultiStats = require("./MultiStats"); | 
					
						
							| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | function MultiCompiler(compilers) { | 
					
						
							|  |  |  | 	Tapable.call(this); | 
					
						
							| 
									
										
										
										
											2015-07-16 06:19:23 +08:00
										 |  |  | 	if(!Array.isArray(compilers)) { | 
					
						
							| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | 		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"); | 
					
						
							| 
									
										
										
										
											2015-04-24 05:55:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-19 05:02:33 +08:00
										 |  |  | 	Object.defineProperty(this, "outputPath", { | 
					
						
							|  |  |  | 		configurable: false, | 
					
						
							|  |  |  | 		get: function() { | 
					
						
							|  |  |  | 			var commonPath = compilers[0].outputPath; | 
					
						
							| 
									
										
										
										
											2015-07-16 06:19:23 +08:00
										 |  |  | 			for(var i = 1; i < compilers.length; i++) { | 
					
						
							|  |  |  | 				while(compilers[i].outputPath.indexOf(commonPath) !== 0 && /[\/\\]/.test(commonPath)) { | 
					
						
							| 
									
										
										
										
											2014-06-19 05:02:33 +08:00
										 |  |  | 					commonPath = commonPath.replace(/[\/\\][^\/\\]*$/, ""); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-07-16 06:19:23 +08:00
										 |  |  | 			if(!commonPath && compilers[0].outputPath[0] === "/") return "/"; | 
					
						
							| 
									
										
										
										
											2014-06-19 05:02:33 +08:00
										 |  |  | 			return commonPath; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var doneCompilers = 0; | 
					
						
							|  |  |  | 	var compilerStats = []; | 
					
						
							|  |  |  | 	this.compilers.forEach(function(compiler, idx) { | 
					
						
							|  |  |  | 		var compilerDone = false; | 
					
						
							|  |  |  | 		compiler.plugin("done", function(stats) { | 
					
						
							| 
									
										
										
										
											2015-07-16 06:19:23 +08:00
										 |  |  | 			if(!compilerDone) { | 
					
						
							| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | 				compilerDone = true; | 
					
						
							|  |  |  | 				doneCompilers++; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			compilerStats[idx] = stats; | 
					
						
							| 
									
										
										
										
											2015-07-16 06:19:23 +08:00
										 |  |  | 			if(doneCompilers === this.compilers.length) { | 
					
						
							| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | 				this.applyPlugins("done", new MultiStats(compilerStats)); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}.bind(this)); | 
					
						
							|  |  |  | 		compiler.plugin("invalid", function() { | 
					
						
							| 
									
										
										
										
											2015-07-16 06:19:23 +08:00
										 |  |  | 			if(compilerDone) { | 
					
						
							| 
									
										
										
										
											2014-06-12 12:29:39 +08:00
										 |  |  | 				compilerDone = false; | 
					
						
							|  |  |  | 				doneCompilers--; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | 			this.applyPlugins("invalid"); | 
					
						
							| 
									
										
										
										
											2014-06-12 12:29:39 +08:00
										 |  |  | 		}.bind(this)); | 
					
						
							| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | 	}, this); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module.exports = MultiCompiler; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MultiCompiler.prototype = Object.create(Tapable.prototype); | 
					
						
							| 
									
										
										
										
											2015-08-18 19:35:57 +08:00
										 |  |  | MultiCompiler.prototype.constructor = MultiCompiler; | 
					
						
							| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | function runWithDependencies(compilers, fn, callback) { | 
					
						
							|  |  |  | 	var fulfilledNames = {}; | 
					
						
							|  |  |  | 	var remainingCompilers = compilers; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function isDependencyFulfilled(d) { | 
					
						
							|  |  |  | 		return fulfilledNames[d]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function getReadyCompilers() { | 
					
						
							|  |  |  | 		var readyCompilers = []; | 
					
						
							|  |  |  | 		var list = remainingCompilers; | 
					
						
							|  |  |  | 		remainingCompilers = []; | 
					
						
							|  |  |  | 		for(var i = 0; i < list.length; i++) { | 
					
						
							|  |  |  | 			var c = list[i]; | 
					
						
							|  |  |  | 			var ready = !c.dependencies || c.dependencies.every(isDependencyFulfilled); | 
					
						
							|  |  |  | 			if(ready) | 
					
						
							|  |  |  | 				readyCompilers.push(c); | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				remainingCompilers.push(c); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return readyCompilers; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function runCompilers(callback) { | 
					
						
							|  |  |  | 		if(remainingCompilers.length === 0) return callback(); | 
					
						
							| 
									
										
										
										
											2017-04-05 21:06:23 +08:00
										 |  |  | 		asyncLib.map(getReadyCompilers(), function(compiler, callback) { | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | 			fn(compiler, function(err) { | 
					
						
							|  |  |  | 				if(err) return callback(err); | 
					
						
							|  |  |  | 				fulfilledNames[compiler.name] = true; | 
					
						
							|  |  |  | 				runCompilers(callback); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}, callback); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	runCompilers(callback); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MultiCompiler.prototype.watch = function(watchOptions, handler) { | 
					
						
							|  |  |  | 	var watchings = []; | 
					
						
							| 
									
										
										
										
											2016-09-07 20:57:53 +08:00
										 |  |  | 	var allStats = this.compilers.map(function() { | 
					
						
							|  |  |  | 		return null; | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | 	var compilerStatus = this.compilers.map(function() { | 
					
						
							|  |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | 	runWithDependencies(this.compilers, function(compiler, callback) { | 
					
						
							|  |  |  | 		var compilerIdx = this.compilers.indexOf(compiler); | 
					
						
							|  |  |  | 		var firstRun = true; | 
					
						
							| 
									
										
										
										
											2017-04-04 17:43:48 +08:00
										 |  |  | 		var watching = compiler.watch(Array.isArray(watchOptions) ? watchOptions[compilerIdx] : watchOptions, function(err, stats) { | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | 			if(err) | 
					
						
							|  |  |  | 				handler(err); | 
					
						
							|  |  |  | 			if(stats) { | 
					
						
							| 
									
										
										
										
											2016-09-07 20:57:53 +08:00
										 |  |  | 				allStats[compilerIdx] = stats; | 
					
						
							| 
									
										
										
										
											2017-01-05 13:46:13 +08:00
										 |  |  | 				compilerStatus[compilerIdx] = "new"; | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | 				if(compilerStatus.every(Boolean)) { | 
					
						
							| 
									
										
										
										
											2017-01-05 13:46:13 +08:00
										 |  |  | 					var freshStats = allStats.filter(function(s, idx) { | 
					
						
							|  |  |  | 						return compilerStatus[idx] === "new"; | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					compilerStatus.fill(true); | 
					
						
							|  |  |  | 					var multiStats = new MultiStats(freshStats); | 
					
						
							| 
									
										
										
										
											2017-01-11 17:51:58 +08:00
										 |  |  | 					handler(null, multiStats); | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if(firstRun && !err) { | 
					
						
							|  |  |  | 				firstRun = false; | 
					
						
							|  |  |  | 				callback(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		watchings.push(watching); | 
					
						
							|  |  |  | 	}.bind(this), function() { | 
					
						
							|  |  |  | 		// ignore
 | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-06 11:32:34 +08:00
										 |  |  | 	return new MultiWatching(watchings, this); | 
					
						
							| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MultiCompiler.prototype.run = function(callback) { | 
					
						
							| 
									
										
										
										
											2016-09-07 20:57:53 +08:00
										 |  |  | 	var allStats = this.compilers.map(function() { | 
					
						
							|  |  |  | 		return null; | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	runWithDependencies(this.compilers, function(compiler, callback) { | 
					
						
							| 
									
										
										
										
											2016-09-07 20:57:53 +08:00
										 |  |  | 		var compilerIdx = this.compilers.indexOf(compiler); | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | 		compiler.run(function(err, stats) { | 
					
						
							|  |  |  | 			if(err) return callback(err); | 
					
						
							| 
									
										
										
										
											2016-09-07 20:57:53 +08:00
										 |  |  | 			allStats[compilerIdx] = stats; | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | 			callback(); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2016-09-07 20:57:53 +08:00
										 |  |  | 	}.bind(this), function(err) { | 
					
						
							| 
									
										
										
										
											2015-07-16 06:19:23 +08:00
										 |  |  | 		if(err) return callback(err); | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | 		callback(null, new MultiStats(allStats)); | 
					
						
							| 
									
										
										
										
											2014-06-12 04:26:50 +08:00
										 |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-12 04:52:02 +08:00
										 |  |  | MultiCompiler.prototype.purgeInputFileSystem = function() { | 
					
						
							|  |  |  | 	this.compilers.forEach(function(compiler) { | 
					
						
							| 
									
										
										
										
											2015-07-16 06:19:23 +08:00
										 |  |  | 		if(compiler.inputFileSystem && compiler.inputFileSystem.purge) | 
					
						
							| 
									
										
										
										
											2014-06-12 04:52:02 +08:00
										 |  |  | 			compiler.inputFileSystem.purge(); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; |