webpack
Version:
Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.
212 lines (190 loc) • 4.91 kB
JavaScript
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const Stats = require("./Stats");
class Watching {
constructor(compiler, watchOptions, handler) {
this.startTime = null;
this.invalid = false;
this.handler = handler;
this.callbacks = [];
this.closed = false;
this.suspended = false;
if (typeof watchOptions === "number") {
this.watchOptions = {
aggregateTimeout: watchOptions
};
} else if (watchOptions && typeof watchOptions === "object") {
this.watchOptions = Object.assign({}, watchOptions);
} else {
this.watchOptions = {};
}
this.watchOptions.aggregateTimeout =
this.watchOptions.aggregateTimeout || 200;
this.compiler = compiler;
this.running = true;
this.compiler.readRecords(err => {
if (err) return this._done(err);
this._go();
});
}
_go() {
this.startTime = Date.now();
this.running = true;
this.invalid = false;
this.compiler.hooks.watchRun.callAsync(this.compiler, err => {
if (err) return this._done(err);
const onCompiled = (err, compilation) => {
if (err) return this._done(err);
if (this.invalid) return this._done();
if (this.compiler.hooks.shouldEmit.call(compilation) === false) {
return this._done(null, compilation);
}
this.compiler.emitAssets(compilation, err => {
if (err) return this._done(err);
if (this.invalid) return this._done();
this.compiler.emitRecords(err => {
if (err) return this._done(err);
if (compilation.hooks.needAdditionalPass.call()) {
compilation.needAdditionalPass = true;
const stats = new Stats(compilation);
stats.startTime = this.startTime;
stats.endTime = Date.now();
this.compiler.hooks.done.callAsync(stats, err => {
if (err) return this._done(err);
this.compiler.hooks.additionalPass.callAsync(err => {
if (err) return this._done(err);
this.compiler.compile(onCompiled);
});
});
return;
}
return this._done(null, compilation);
});
});
};
this.compiler.compile(onCompiled);
});
}
_getStats(compilation) {
const stats = new Stats(compilation);
stats.startTime = this.startTime;
stats.endTime = Date.now();
return stats;
}
_done(err, compilation) {
this.running = false;
if (this.invalid) return this._go();
const stats = compilation ? this._getStats(compilation) : null;
if (err) {
this.compiler.hooks.failed.call(err);
this.handler(err, stats);
return;
}
this.compiler.hooks.done.callAsync(stats, () => {
this.handler(null, stats);
if (!this.closed) {
this.watch(
Array.from(compilation.fileDependencies),
Array.from(compilation.contextDependencies),
Array.from(compilation.missingDependencies)
);
}
for (const cb of this.callbacks) cb();
this.callbacks.length = 0;
});
}
watch(files, dirs, missing) {
this.pausedWatcher = null;
this.watcher = this.compiler.watchFileSystem.watch(
files,
dirs,
missing,
this.startTime,
this.watchOptions,
(
err,
filesModified,
contextModified,
missingModified,
fileTimestamps,
contextTimestamps,
removedFiles
) => {
this.pausedWatcher = this.watcher;
this.watcher = null;
if (err) {
return this.handler(err);
}
this.compiler.fileTimestamps = fileTimestamps;
this.compiler.contextTimestamps = contextTimestamps;
this.compiler.removedFiles = removedFiles;
if (!this.suspended) {
this._invalidate();
}
},
(fileName, changeTime) => {
this.compiler.hooks.invalid.call(fileName, changeTime);
}
);
}
invalidate(callback) {
if (callback) {
this.callbacks.push(callback);
}
if (this.watcher) {
this.compiler.fileTimestamps = this.watcher.getFileTimestamps();
this.compiler.contextTimestamps = this.watcher.getContextTimestamps();
}
return this._invalidate();
}
_invalidate() {
if (this.watcher) {
this.pausedWatcher = this.watcher;
this.watcher.pause();
this.watcher = null;
}
if (this.running) {
this.invalid = true;
return false;
} else {
this._go();
}
}
suspend() {
this.suspended = true;
this.invalid = false;
}
resume() {
if (this.suspended) {
this.suspended = false;
this._invalidate();
}
}
close(callback) {
const finalCallback = () => {
this.compiler.hooks.watchClose.call();
this.compiler.running = false;
this.compiler.watchMode = false;
if (callback !== undefined) callback();
};
this.closed = true;
if (this.watcher) {
this.watcher.close();
this.watcher = null;
}
if (this.pausedWatcher) {
this.pausedWatcher.close();
this.pausedWatcher = null;
}
if (this.running) {
this.invalid = true;
this._done = finalCallback;
} else {
finalCallback();
}
}
}
module.exports = Watching;