Skip to content

Commit 12b3751

Browse files
authored
Merge pull request webpack#6691 from acupofspirt/master
Prevent webpack from running twice at a time
2 parents 977bdb9 + ccc32d3 commit 12b3751

7 files changed

+344
-21
lines changed

lib/Compiler.js

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const ResolverFactory = require("./ResolverFactory");
2222

2323
const RequestShortener = require("./RequestShortener");
2424
const makePathsRelative = require("./util/identifier").makePathsRelative;
25+
const ConcurrentCompilationError = require("./ConcurrentCompilationError");
2526

2627
class Compiler extends Tapable {
2728
constructor(context) {
@@ -129,33 +130,48 @@ class Compiler extends Tapable {
129130
this.context = context;
130131

131132
this.requestShortener = new RequestShortener(context);
133+
134+
this.running = false;
132135
}
133136

134137
watch(watchOptions, handler) {
138+
if (this.running) return handler(new ConcurrentCompilationError());
139+
140+
this.running = true;
135141
this.fileTimestamps = new Map();
136142
this.contextTimestamps = new Map();
137143
return new Watching(this, watchOptions, handler);
138144
}
139145

140146
run(callback) {
147+
if (this.running) return callback(new ConcurrentCompilationError());
148+
149+
const finalCallback = (err, stats) => {
150+
this.running = false;
151+
152+
if (callback !== undefined) return callback(err, stats);
153+
};
154+
141155
const startTime = Date.now();
142156

157+
this.running = true;
158+
143159
const onCompiled = (err, compilation) => {
144-
if (err) return callback(err);
160+
if (err) return finalCallback(err);
145161

146162
if (this.hooks.shouldEmit.call(compilation) === false) {
147163
const stats = new Stats(compilation);
148164
stats.startTime = startTime;
149165
stats.endTime = Date.now();
150166
this.hooks.done.callAsync(stats, err => {
151-
if (err) return callback(err);
152-
return callback(null, stats);
167+
if (err) return finalCallback(err);
168+
return finalCallback(null, stats);
153169
});
154170
return;
155171
}
156172

157173
this.emitAssets(compilation, err => {
158-
if (err) return callback(err);
174+
if (err) return finalCallback(err);
159175

160176
if (compilation.hooks.needAdditionalPass.call()) {
161177
compilation.needAdditionalPass = true;
@@ -164,38 +180,38 @@ class Compiler extends Tapable {
164180
stats.startTime = startTime;
165181
stats.endTime = Date.now();
166182
this.hooks.done.callAsync(stats, err => {
167-
if (err) return callback(err);
183+
if (err) return finalCallback(err);
168184

169185
this.hooks.additionalPass.callAsync(err => {
170-
if (err) return callback(err);
186+
if (err) return finalCallback(err);
171187
this.compile(onCompiled);
172188
});
173189
});
174190
return;
175191
}
176192

177193
this.emitRecords(err => {
178-
if (err) return callback(err);
194+
if (err) return finalCallback(err);
179195

180196
const stats = new Stats(compilation);
181197
stats.startTime = startTime;
182198
stats.endTime = Date.now();
183199
this.hooks.done.callAsync(stats, err => {
184-
if (err) return callback(err);
185-
return callback(null, stats);
200+
if (err) return finalCallback(err);
201+
return finalCallback(null, stats);
186202
});
187203
});
188204
});
189205
};
190206

191207
this.hooks.beforeRun.callAsync(this, err => {
192-
if (err) return callback(err);
208+
if (err) return finalCallback(err);
193209

194210
this.hooks.run.callAsync(this, err => {
195-
if (err) return callback(err);
211+
if (err) return finalCallback(err);
196212

197213
this.readRecords(err => {
198-
if (err) return callback(err);
214+
if (err) return finalCallback(err);
199215

200216
this.compile(onCompiled);
201217
});

lib/ConcurrentCompilationError.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Maksim Nazarjev @acupofspirt
4+
*/
5+
"use strict";
6+
7+
const WebpackError = require("./WebpackError");
8+
9+
module.exports = class ConcurrentCompilationError extends WebpackError {
10+
constructor() {
11+
super();
12+
13+
this.name = "ConcurrentCompilationError";
14+
this.message =
15+
"You ran Webpack twice. Each instance only supports a single concurrent compilation at a time.";
16+
17+
Error.captureStackTrace(this, this.constructor);
18+
}
19+
};

lib/MultiCompiler.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const MultiHook = require("tapable").MultiHook;
1010
const asyncLib = require("neo-async");
1111
const MultiWatching = require("./MultiWatching");
1212
const MultiStats = require("./MultiStats");
13+
const ConcurrentCompilationError = require("./ConcurrentCompilationError");
1314

1415
module.exports = class MultiCompiler extends Tapable {
1516
constructor(compilers) {
@@ -53,6 +54,7 @@ module.exports = class MultiCompiler extends Tapable {
5354
}
5455
});
5556
}
57+
this.running = false;
5658
}
5759

5860
get outputPath() {
@@ -185,10 +187,13 @@ module.exports = class MultiCompiler extends Tapable {
185187
}
186188

187189
watch(watchOptions, handler) {
190+
if (this.running) return handler(new ConcurrentCompilationError());
191+
188192
let watchings = [];
189193
let allStats = this.compilers.map(() => null);
190194
let compilerStatus = this.compilers.map(() => false);
191195
if (this.validateDependencies(handler)) {
196+
this.running = true;
192197
this.runWithDependencies(
193198
this.compilers,
194199
(compiler, callback) => {
@@ -230,8 +235,17 @@ module.exports = class MultiCompiler extends Tapable {
230235
}
231236

232237
run(callback) {
238+
if (this.running) return callback(new ConcurrentCompilationError());
239+
240+
const finalCallback = (err, stats) => {
241+
this.running = false;
242+
243+
if (callback !== undefined) return callback(err, stats);
244+
};
245+
233246
const allStats = this.compilers.map(() => null);
234247
if (this.validateDependencies(callback)) {
248+
this.running = true;
235249
this.runWithDependencies(
236250
this.compilers,
237251
(compiler, callback) => {
@@ -243,8 +257,8 @@ module.exports = class MultiCompiler extends Tapable {
243257
});
244258
},
245259
err => {
246-
if (err) return callback(err);
247-
callback(null, new MultiStats(allStats));
260+
if (err) return finalCallback(err);
261+
finalCallback(null, new MultiStats(allStats));
248262
}
249263
);
250264
}

lib/MultiWatching.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class MultiWatching {
2727
err => {
2828
this.compiler.hooks.watchClose.call();
2929
if (typeof callback === "function") {
30+
this.compiler.running = false;
3031
callback(err);
3132
}
3233
}

lib/Watching.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,11 @@ class Watching {
166166
}
167167

168168
close(callback) {
169-
if (callback === undefined) callback = () => {};
169+
const finalCallback = () => {
170+
this.compiler.hooks.watchClose.call();
171+
this.compiler.running = false;
172+
if (callback !== undefined) callback();
173+
};
170174

171175
this.closed = true;
172176
if (this.watcher) {
@@ -179,13 +183,9 @@ class Watching {
179183
}
180184
if (this.running) {
181185
this.invalid = true;
182-
this._done = () => {
183-
this.compiler.hooks.watchClose.call();
184-
callback();
185-
};
186+
this._done = finalCallback;
186187
} else {
187-
this.compiler.hooks.watchClose.call();
188-
callback();
188+
finalCallback();
189189
}
190190
}
191191
}

0 commit comments

Comments
 (0)