UNPKG

4.68 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5"use strict";
6
7const Stats = require("./Stats");
8
9class Watching {
10 constructor(compiler, watchOptions, handler) {
11 this.startTime = null;
12 this.invalid = false;
13 this.handler = handler;
14 this.callbacks = [];
15 this.closed = false;
16 if (typeof watchOptions === "number") {
17 this.watchOptions = {
18 aggregateTimeout: watchOptions
19 };
20 } else if (watchOptions && typeof watchOptions === "object") {
21 this.watchOptions = Object.assign({}, watchOptions);
22 } else {
23 this.watchOptions = {};
24 }
25 this.watchOptions.aggregateTimeout =
26 this.watchOptions.aggregateTimeout || 200;
27 this.compiler = compiler;
28 this.running = true;
29 this.compiler.readRecords(err => {
30 if (err) return this._done(err);
31
32 this._go();
33 });
34 }
35
36 _go() {
37 this.startTime = Date.now();
38 this.running = true;
39 this.invalid = false;
40 this.compiler.hooks.watchRun.callAsync(this.compiler, err => {
41 if (err) return this._done(err);
42 const onCompiled = (err, compilation) => {
43 if (err) return this._done(err);
44 if (this.invalid) return this._done();
45
46 if (this.compiler.hooks.shouldEmit.call(compilation) === false) {
47 return this._done(null, compilation);
48 }
49
50 this.compiler.emitAssets(compilation, err => {
51 if (err) return this._done(err);
52 if (this.invalid) return this._done();
53 this.compiler.emitRecords(err => {
54 if (err) return this._done(err);
55
56 if (compilation.hooks.needAdditionalPass.call()) {
57 compilation.needAdditionalPass = true;
58
59 const stats = new Stats(compilation);
60 stats.startTime = this.startTime;
61 stats.endTime = Date.now();
62 this.compiler.hooks.done.callAsync(stats, err => {
63 if (err) return this._done(err);
64
65 this.compiler.hooks.additionalPass.callAsync(err => {
66 if (err) return this._done(err);
67 this.compiler.compile(onCompiled);
68 });
69 });
70 return;
71 }
72 return this._done(null, compilation);
73 });
74 });
75 };
76 this.compiler.compile(onCompiled);
77 });
78 }
79
80 _getStats(compilation) {
81 const stats = new Stats(compilation);
82 stats.startTime = this.startTime;
83 stats.endTime = Date.now();
84 return stats;
85 }
86
87 _done(err, compilation) {
88 this.running = false;
89 if (this.invalid) return this._go();
90
91 const stats = compilation ? this._getStats(compilation) : null;
92 if (err) {
93 this.compiler.hooks.failed.call(err);
94 this.handler(err, stats);
95 return;
96 }
97 this.compiler.hooks.done.callAsync(stats, () => {
98 this.handler(null, stats);
99 if (!this.closed) {
100 this.watch(
101 Array.from(compilation.fileDependencies),
102 Array.from(compilation.contextDependencies),
103 Array.from(compilation.missingDependencies)
104 );
105 }
106 for (const cb of this.callbacks) cb();
107 this.callbacks.length = 0;
108 });
109 }
110
111 watch(files, dirs, missing) {
112 this.pausedWatcher = null;
113 this.watcher = this.compiler.watchFileSystem.watch(
114 files,
115 dirs,
116 missing,
117 this.startTime,
118 this.watchOptions,
119 (
120 err,
121 filesModified,
122 contextModified,
123 missingModified,
124 fileTimestamps,
125 contextTimestamps,
126 removedFiles
127 ) => {
128 this.pausedWatcher = this.watcher;
129 this.watcher = null;
130 if (err) {
131 return this.handler(err);
132 }
133 this.compiler.fileTimestamps = fileTimestamps;
134 this.compiler.contextTimestamps = contextTimestamps;
135 this.compiler.removedFiles = removedFiles;
136 this._invalidate();
137 },
138 (fileName, changeTime) => {
139 this.compiler.hooks.invalid.call(fileName, changeTime);
140 }
141 );
142 }
143
144 invalidate(callback) {
145 if (callback) {
146 this.callbacks.push(callback);
147 }
148 if (this.watcher) {
149 this.compiler.fileTimestamps = this.watcher.getFileTimestamps();
150 this.compiler.contextTimestamps = this.watcher.getContextTimestamps();
151 }
152 return this._invalidate();
153 }
154
155 _invalidate() {
156 if (this.watcher) {
157 this.pausedWatcher = this.watcher;
158 this.watcher.pause();
159 this.watcher = null;
160 }
161 if (this.running) {
162 this.invalid = true;
163 return false;
164 } else {
165 this._go();
166 }
167 }
168
169 close(callback) {
170 const finalCallback = () => {
171 this.compiler.hooks.watchClose.call();
172 this.compiler.running = false;
173 this.compiler.watchMode = false;
174 if (callback !== undefined) callback();
175 };
176
177 this.closed = true;
178 if (this.watcher) {
179 this.watcher.close();
180 this.watcher = null;
181 }
182 if (this.pausedWatcher) {
183 this.pausedWatcher.close();
184 this.pausedWatcher = null;
185 }
186 if (this.running) {
187 this.invalid = true;
188 this._done = finalCallback;
189 } else {
190 finalCallback();
191 }
192 }
193}
194
195module.exports = Watching;