source: trip-planner-front/node_modules/webpack/lib/Watching.js@ 84d0fbb

Last change on this file since 84d0fbb was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 12.2 KB
RevLine 
[6a3a178]1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const Stats = require("./Stats");
9
10/** @typedef {import("../declarations/WebpackOptions").WatchOptions} WatchOptions */
11/** @typedef {import("./Compilation")} Compilation */
12/** @typedef {import("./Compiler")} Compiler */
13/** @typedef {import("./FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */
14
15/**
16 * @template T
17 * @callback Callback
18 * @param {Error=} err
19 * @param {T=} result
20 */
21
22class Watching {
23 /**
24 * @param {Compiler} compiler the compiler
25 * @param {WatchOptions} watchOptions options
26 * @param {Callback<Stats>} handler completion handler
27 */
28 constructor(compiler, watchOptions, handler) {
29 this.startTime = null;
30 this.invalid = false;
31 this.handler = handler;
32 /** @type {Callback<void>[]} */
33 this.callbacks = [];
34 /** @type {Callback<void>[] | undefined} */
35 this._closeCallbacks = undefined;
36 this.closed = false;
37 this.suspended = false;
38 this.blocked = false;
39 this._isBlocked = () => false;
40 this._onChange = () => {};
41 this._onInvalid = () => {};
42 if (typeof watchOptions === "number") {
43 this.watchOptions = {
44 aggregateTimeout: watchOptions
45 };
46 } else if (watchOptions && typeof watchOptions === "object") {
47 this.watchOptions = { ...watchOptions };
48 } else {
49 this.watchOptions = {};
50 }
51 if (typeof this.watchOptions.aggregateTimeout !== "number") {
52 this.watchOptions.aggregateTimeout = 200;
53 }
54 this.compiler = compiler;
55 this.running = false;
56 this._initial = true;
57 this._invalidReported = true;
58 this._needRecords = true;
59 this.watcher = undefined;
60 this.pausedWatcher = undefined;
61 /** @type {Set<string>} */
62 this._collectedChangedFiles = undefined;
63 /** @type {Set<string>} */
64 this._collectedRemovedFiles = undefined;
65 this._done = this._done.bind(this);
66 process.nextTick(() => {
67 if (this._initial) this._invalidate();
68 });
69 }
70
71 /**
72 * @param {ReadonlySet<string>} changedFiles changed files
73 * @param {ReadonlySet<string>} removedFiles removed files
74 */
75 _mergeWithCollected(changedFiles, removedFiles) {
76 if (!changedFiles) return;
77 if (!this._collectedChangedFiles) {
78 this._collectedChangedFiles = new Set(changedFiles);
79 this._collectedRemovedFiles = new Set(removedFiles);
80 } else {
81 for (const file of changedFiles) {
82 this._collectedChangedFiles.add(file);
83 this._collectedRemovedFiles.delete(file);
84 }
85 for (const file of removedFiles) {
86 this._collectedChangedFiles.delete(file);
87 this._collectedRemovedFiles.add(file);
88 }
89 }
90 }
91
92 /**
93 * @param {ReadonlyMap<string, FileSystemInfoEntry | "ignore">=} fileTimeInfoEntries info for files
94 * @param {ReadonlyMap<string, FileSystemInfoEntry | "ignore">=} contextTimeInfoEntries info for directories
95 * @param {ReadonlySet<string>=} changedFiles changed files
96 * @param {ReadonlySet<string>=} removedFiles removed files
97 * @returns {void}
98 */
99 _go(fileTimeInfoEntries, contextTimeInfoEntries, changedFiles, removedFiles) {
100 this._initial = false;
101 if (this.startTime === null) this.startTime = Date.now();
102 this.running = true;
103 if (this.watcher) {
104 this.pausedWatcher = this.watcher;
105 this.lastWatcherStartTime = Date.now();
106 this.watcher.pause();
107 this.watcher = null;
108 } else if (!this.lastWatcherStartTime) {
109 this.lastWatcherStartTime = Date.now();
110 }
111 this.compiler.fsStartTime = Date.now();
112 this._mergeWithCollected(
113 changedFiles ||
114 (this.pausedWatcher &&
115 this.pausedWatcher.getAggregatedChanges &&
116 this.pausedWatcher.getAggregatedChanges()),
117 (this.compiler.removedFiles =
118 removedFiles ||
119 (this.pausedWatcher &&
120 this.pausedWatcher.getAggregatedRemovals &&
121 this.pausedWatcher.getAggregatedRemovals()))
122 );
123
124 this.compiler.modifiedFiles = this._collectedChangedFiles;
125 this._collectedChangedFiles = undefined;
126 this.compiler.removedFiles = this._collectedRemovedFiles;
127 this._collectedRemovedFiles = undefined;
128
129 this.compiler.fileTimestamps =
130 fileTimeInfoEntries ||
131 (this.pausedWatcher && this.pausedWatcher.getFileTimeInfoEntries());
132 this.compiler.contextTimestamps =
133 contextTimeInfoEntries ||
134 (this.pausedWatcher && this.pausedWatcher.getContextTimeInfoEntries());
135
136 const run = () => {
137 if (this.compiler.idle) {
138 return this.compiler.cache.endIdle(err => {
139 if (err) return this._done(err);
140 this.compiler.idle = false;
141 run();
142 });
143 }
144 if (this._needRecords) {
145 return this.compiler.readRecords(err => {
146 if (err) return this._done(err);
147
148 this._needRecords = false;
149 run();
150 });
151 }
152 this.invalid = false;
153 this._invalidReported = false;
154 this.compiler.hooks.watchRun.callAsync(this.compiler, err => {
155 if (err) return this._done(err);
156 const onCompiled = (err, compilation) => {
157 if (err) return this._done(err, compilation);
158 if (this.invalid) return this._done(null, compilation);
159
160 if (this.compiler.hooks.shouldEmit.call(compilation) === false) {
161 return this._done(null, compilation);
162 }
163
164 process.nextTick(() => {
165 const logger = compilation.getLogger("webpack.Compiler");
166 logger.time("emitAssets");
167 this.compiler.emitAssets(compilation, err => {
168 logger.timeEnd("emitAssets");
169 if (err) return this._done(err, compilation);
170 if (this.invalid) return this._done(null, compilation);
171
172 logger.time("emitRecords");
173 this.compiler.emitRecords(err => {
174 logger.timeEnd("emitRecords");
175 if (err) return this._done(err, compilation);
176
177 if (compilation.hooks.needAdditionalPass.call()) {
178 compilation.needAdditionalPass = true;
179
180 compilation.startTime = this.startTime;
181 compilation.endTime = Date.now();
182 logger.time("done hook");
183 const stats = new Stats(compilation);
184 this.compiler.hooks.done.callAsync(stats, err => {
185 logger.timeEnd("done hook");
186 if (err) return this._done(err, compilation);
187
188 this.compiler.hooks.additionalPass.callAsync(err => {
189 if (err) return this._done(err, compilation);
190 this.compiler.compile(onCompiled);
191 });
192 });
193 return;
194 }
195 return this._done(null, compilation);
196 });
197 });
198 });
199 };
200 this.compiler.compile(onCompiled);
201 });
202 };
203
204 run();
205 }
206
207 /**
208 * @param {Compilation} compilation the compilation
209 * @returns {Stats} the compilation stats
210 */
211 _getStats(compilation) {
212 const stats = new Stats(compilation);
213 return stats;
214 }
215
216 /**
217 * @param {Error=} err an optional error
218 * @param {Compilation=} compilation the compilation
219 * @returns {void}
220 */
221 _done(err, compilation) {
222 this.running = false;
223
224 const logger = compilation && compilation.getLogger("webpack.Watching");
225
226 let stats = null;
227
228 const handleError = (err, cbs) => {
229 this.compiler.hooks.failed.call(err);
230 this.compiler.cache.beginIdle();
231 this.compiler.idle = true;
232 this.handler(err, stats);
233 if (!cbs) {
234 cbs = this.callbacks;
235 this.callbacks = [];
236 }
237 for (const cb of cbs) cb(err);
238 };
239
240 if (
241 this.invalid &&
242 !this.suspended &&
243 !this.blocked &&
244 !(this._isBlocked() && (this.blocked = true))
245 ) {
246 if (compilation) {
247 logger.time("storeBuildDependencies");
248 this.compiler.cache.storeBuildDependencies(
249 compilation.buildDependencies,
250 err => {
251 logger.timeEnd("storeBuildDependencies");
252 if (err) return handleError(err);
253 this._go();
254 }
255 );
256 } else {
257 this._go();
258 }
259 return;
260 }
261
262 if (compilation) {
263 compilation.startTime = this.startTime;
264 compilation.endTime = Date.now();
265 stats = new Stats(compilation);
266 }
267 this.startTime = null;
268 if (err) return handleError(err);
269
270 const cbs = this.callbacks;
271 this.callbacks = [];
272 logger.time("done hook");
273 this.compiler.hooks.done.callAsync(stats, err => {
274 logger.timeEnd("done hook");
275 if (err) return handleError(err, cbs);
276 this.handler(null, stats);
277 logger.time("storeBuildDependencies");
278 this.compiler.cache.storeBuildDependencies(
279 compilation.buildDependencies,
280 err => {
281 logger.timeEnd("storeBuildDependencies");
282 if (err) return handleError(err, cbs);
283 logger.time("beginIdle");
284 this.compiler.cache.beginIdle();
285 this.compiler.idle = true;
286 logger.timeEnd("beginIdle");
287 process.nextTick(() => {
288 if (!this.closed) {
289 this.watch(
290 compilation.fileDependencies,
291 compilation.contextDependencies,
292 compilation.missingDependencies
293 );
294 }
295 });
296 for (const cb of cbs) cb(null);
297 this.compiler.hooks.afterDone.call(stats);
298 }
299 );
300 });
301 }
302
303 /**
304 * @param {Iterable<string>} files watched files
305 * @param {Iterable<string>} dirs watched directories
306 * @param {Iterable<string>} missing watched existence entries
307 * @returns {void}
308 */
309 watch(files, dirs, missing) {
310 this.pausedWatcher = null;
311 this.watcher = this.compiler.watchFileSystem.watch(
312 files,
313 dirs,
314 missing,
315 this.lastWatcherStartTime,
316 this.watchOptions,
317 (
318 err,
319 fileTimeInfoEntries,
320 contextTimeInfoEntries,
321 changedFiles,
322 removedFiles
323 ) => {
324 if (err) {
325 this.compiler.modifiedFiles = undefined;
326 this.compiler.removedFiles = undefined;
327 this.compiler.fileTimestamps = undefined;
328 this.compiler.contextTimestamps = undefined;
329 this.compiler.fsStartTime = undefined;
330 return this.handler(err);
331 }
332 this._invalidate(
333 fileTimeInfoEntries,
334 contextTimeInfoEntries,
335 changedFiles,
336 removedFiles
337 );
338 this._onChange();
339 },
340 (fileName, changeTime) => {
341 if (!this._invalidReported) {
342 this._invalidReported = true;
343 this.compiler.hooks.invalid.call(fileName, changeTime);
344 }
345 this._onInvalid();
346 }
347 );
348 }
349
350 /**
351 * @param {Callback<void>=} callback signals when the build has completed again
352 * @returns {void}
353 */
354 invalidate(callback) {
355 if (callback) {
356 this.callbacks.push(callback);
357 }
358 if (!this._invalidReported) {
359 this._invalidReported = true;
360 this.compiler.hooks.invalid.call(null, Date.now());
361 }
362 this._onChange();
363 this._invalidate();
364 }
365
366 _invalidate(
367 fileTimeInfoEntries,
368 contextTimeInfoEntries,
369 changedFiles,
370 removedFiles
371 ) {
372 if (this.suspended || (this._isBlocked() && (this.blocked = true))) {
373 this._mergeWithCollected(changedFiles, removedFiles);
374 return;
375 }
376
377 if (this.running) {
378 this._mergeWithCollected(changedFiles, removedFiles);
379 this.invalid = true;
380 } else {
381 this._go(
382 fileTimeInfoEntries,
383 contextTimeInfoEntries,
384 changedFiles,
385 removedFiles
386 );
387 }
388 }
389
390 suspend() {
391 this.suspended = true;
392 }
393
394 resume() {
395 if (this.suspended) {
396 this.suspended = false;
397 this._invalidate();
398 }
399 }
400
401 /**
402 * @param {Callback<void>} callback signals when the watcher is closed
403 * @returns {void}
404 */
405 close(callback) {
406 if (this._closeCallbacks) {
407 if (callback) {
408 this._closeCallbacks.push(callback);
409 }
410 return;
411 }
412 const finalCallback = (err, compilation) => {
413 this.running = false;
414 this.compiler.running = false;
415 this.compiler.watching = undefined;
416 this.compiler.watchMode = false;
417 this.compiler.modifiedFiles = undefined;
418 this.compiler.removedFiles = undefined;
419 this.compiler.fileTimestamps = undefined;
420 this.compiler.contextTimestamps = undefined;
421 this.compiler.fsStartTime = undefined;
422 const shutdown = () => {
423 this.compiler.cache.shutdown(err => {
424 this.compiler.hooks.watchClose.call();
425 const closeCallbacks = this._closeCallbacks;
426 this._closeCallbacks = undefined;
427 for (const cb of closeCallbacks) cb(err);
428 });
429 };
430 if (compilation) {
431 const logger = compilation.getLogger("webpack.Watching");
432 logger.time("storeBuildDependencies");
433 this.compiler.cache.storeBuildDependencies(
434 compilation.buildDependencies,
435 err => {
436 logger.timeEnd("storeBuildDependencies");
437 shutdown();
438 }
439 );
440 } else {
441 shutdown();
442 }
443 };
444
445 this.closed = true;
446 if (this.watcher) {
447 this.watcher.close();
448 this.watcher = null;
449 }
450 if (this.pausedWatcher) {
451 this.pausedWatcher.close();
452 this.pausedWatcher = null;
453 }
454 this._closeCallbacks = [];
455 if (callback) {
456 this._closeCallbacks.push(callback);
457 }
458 if (this.running) {
459 this.invalid = true;
460 this._done = finalCallback;
461 } else {
462 finalCallback();
463 }
464 }
465}
466
467module.exports = Watching;
Note: See TracBrowser for help on using the repository browser.