From 9f60f506444c795f6db57f6513c72f4e77f7a874 Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 7 Mar 2018 13:45:38 +0300 Subject: [PATCH] Prevent multi compiler from running twice at a time --- lib/MultiCompiler.js | 39 ++++++++++++-- lib/MultiWatching.js | 1 + test/MultiCompiler.test.js | 101 +++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 5 deletions(-) diff --git a/lib/MultiCompiler.js b/lib/MultiCompiler.js index 31a504dbb..574baeec0 100644 --- a/lib/MultiCompiler.js +++ b/lib/MultiCompiler.js @@ -53,6 +53,7 @@ module.exports = class MultiCompiler extends Tapable { } }); } + this.running = false; } get outputPath() { @@ -185,10 +186,24 @@ module.exports = class MultiCompiler extends Tapable { } watch(watchOptions, handler) { + if (this.running) + return handler( + new Error( + "You ran Webpack twice. Each instance only supports a single concurrent compilation at a time." + ) + ); + + const finalHandler = (err, stats) => { + this.running = false; + + if (handler !== undefined) handler(err, stats); + }; + let watchings = []; let allStats = this.compilers.map(() => null); let compilerStatus = this.compilers.map(() => false); - if (this.validateDependencies(handler)) { + if (this.validateDependencies(finalHandler)) { + this.running = true; this.runWithDependencies( this.compilers, (compiler, callback) => { @@ -199,7 +214,7 @@ module.exports = class MultiCompiler extends Tapable { ? watchOptions[compilerIdx] : watchOptions, (err, stats) => { - if (err) handler(err); + if (err) finalHandler(err); if (stats) { allStats[compilerIdx] = stats; compilerStatus[compilerIdx] = "new"; @@ -209,7 +224,7 @@ module.exports = class MultiCompiler extends Tapable { }); compilerStatus.fill(true); const multiStats = new MultiStats(freshStats); - handler(null, multiStats); + finalHandler(null, multiStats); } } if (firstRun && !err) { @@ -230,8 +245,22 @@ module.exports = class MultiCompiler extends Tapable { } run(callback) { + if (this.running) + return callback( + new Error( + "You ran Webpack twice. Each instance only supports a single concurrent compilation at a time." + ) + ); + + const finalCallback = (err, stats) => { + this.running = false; + + if (callback !== undefined) return callback(err, stats); + }; + const allStats = this.compilers.map(() => null); if (this.validateDependencies(callback)) { + this.running = true; this.runWithDependencies( this.compilers, (compiler, callback) => { @@ -243,8 +272,8 @@ module.exports = class MultiCompiler extends Tapable { }); }, err => { - if (err) return callback(err); - callback(null, new MultiStats(allStats)); + if (err) return finalCallback(err); + finalCallback(null, new MultiStats(allStats)); } ); } diff --git a/lib/MultiWatching.js b/lib/MultiWatching.js index 80a6a4a53..48e012c87 100644 --- a/lib/MultiWatching.js +++ b/lib/MultiWatching.js @@ -27,6 +27,7 @@ class MultiWatching { err => { this.compiler.hooks.watchClose.call(); if (typeof callback === "function") { + this.compiler.running = false; callback(err); } } diff --git a/test/MultiCompiler.test.js b/test/MultiCompiler.test.js index 2f2f0dad0..bb3a11f7e 100644 --- a/test/MultiCompiler.test.js +++ b/test/MultiCompiler.test.js @@ -52,4 +52,105 @@ describe("MultiCompiler", function() { } }); }); + + it("should not be run twice at a time (run)", function(done) { + const compiler = createMultiCompiler(); + compiler.run((err, stats) => { + if (err) return done(err); + }); + compiler.run((err, stats) => { + if (err) return done(); + }); + }); + it("should not be run twice at a time (watch)", function(done) { + const compiler = createMultiCompiler(); + compiler.watch({}, (err, stats) => { + if (err) return done(err); + }); + compiler.watch({}, (err, stats) => { + if (err) return done(); + }); + }); + it("should not be run twice at a time (run - watch)", function(done) { + const compiler = createMultiCompiler(); + compiler.run((err, stats) => { + if (err) return done(err); + }); + compiler.watch({}, (err, stats) => { + if (err) return done(); + }); + }); + it("should not be run twice at a time (watch - run)", function(done) { + const compiler = createMultiCompiler(); + compiler.watch({}, (err, stats) => { + if (err) return done(err); + }); + compiler.run((err, stats) => { + if (err) return done(); + }); + }); + it("should not be run twice at a time (instance cb)", function(done) { + const compiler = webpack( + { + context: __dirname, + mode: "production", + entry: "./c", + output: { + path: "/", + filename: "bundle.js" + } + }, + () => {} + ); + compiler.outputFileSystem = new MemoryFs(); + compiler.run((err, stats) => { + if (err) return done(); + }); + }); + it("should run again correctly after first compilation", function(done) { + const compiler = createMultiCompiler(); + compiler.run((err, stats) => { + if (err) return done(err); + + compiler.run((err, stats) => { + if (err) return done(err); + done(); + }); + }); + }); + it("should watch again correctly after first compilation", function(done) { + const compiler = createMultiCompiler(); + compiler.run((err, stats) => { + if (err) return done(err); + + compiler.watch({}, (err, stats) => { + if (err) return done(err); + done(); + }); + }); + }); + it("should run again correctly after first closed watch", function(done) { + const compiler = createMultiCompiler(); + const watching = compiler.watch({}, (err, stats) => { + if (err) return done(err); + }); + watching.close(() => { + compiler.run((err, stats) => { + if (err) return done(err); + done(); + }); + }); + }); + it("should watch again correctly after first closed watch", function(done) { + const compiler = createMultiCompiler(); + const watching = compiler.watch({}, (err, stats) => { + if (err) return done(err); + }); + watching.close(() => { + compiler.watch({}, (err, stats) => { + if (err) return done(err); + done(); + }); + }); + }); });