@skylineos/clsp-player
Version:
Skyline Technology Solutions' CLSP Video Player. Stream video in near-real-time in modern browsers.
169 lines (149 loc) • 4.67 kB
JavaScript
'use strict';
/**
* A helper class for the webpack `watch` compiler.
*
* @see - https://webpack.js.org/api/node/
* @see - https://webpack.js.org/api/node/#watching
* @see - https://webpack.js.org/api/compiler-hooks
* @see - https://webpack.js.org/api/compiler-hooks/#done
*
* This helper extends the BuildCompiler, so it inherits all of those console
* messages. This WatchCompiler class also logs a message to the console any
* time a change is detected, and starts a new timer for that update.
*/
const BuildCompiler = require('./BuildCompiler');
module.exports = class WatchCompiler extends BuildCompiler {
/**
* @see - this.constructor
*/
static factory (name, webpackConfigs, watchOptions) {
return new WatchCompiler(name, webpackConfigs, watchOptions);
}
/**
* @constructor
* @private
*
* Create a new WatchCompiler, and register the default webpack compiler
* hooks.
*
* @param {string} name
* The name of the compile job (arbitrary), used for logging
* @param {Array} webpackConfigs
* An array of webpack config objects - @see - https://webpack.js.org/configuration/#options
* @param {Object} watchOptions
* An object containing any watchOptions overrides - @see - https://webpack.js.org/configuration/watch/#watchoptions
*
* @returns {WatchCompiler}
* A new WatchCompiler instance
*/
constructor (name, webpackConfigs = [], watchOptions = {}) {
super(name, webpackConfigs);
this.watchOptions = {
// wait one second before re-transpiling after a change
aggregateTimeout: 1000,
// in vagrant, we cannot rely on file system events, so we must poll :(
// NOTE that if this is set to true, the build will never finish!
poll: process.env.WATCH_WITH_POLLING === 'true' && 2000,
...watchOptions,
};
// Used to track whether or not to log a "change detected" message
this.isFirstCompile = true;
// the webpack watcher
// @see - https://webpack.js.org/api/node/#watching
this.watching = null;
}
/**
* @private
*
* Register additional compiler hooks.
*
* On `watchRun`, indicate that a change was detected if this isn't the first
* time the compilation has run. Also, reset the timer to display how long
* this update compilation has been running.
*
* @returns {void}
*/
initialize () {
super.initialize();
// Called any time a file is changed before compilation
// Called many times on the first compilation
this.compiler.hooks.watchRun.tap(this.name, () => {
console.log(`\n${this.name}:watch:watchRun`);
if (!this.isFirstCompile) {
console.log('');
console.log('Change detected, compiling...');
console.log('');
}
if (!this.timer) {
this.setTimer();
}
});
// Called when a compilation has finished
this.compiler.hooks.done.tap(this.name, (stats) => {
console.log(`${this.name}:watch:done`);
this.isFirstCompile = false;
});
}
/**
* `build` is not a supported method, so calling this will ALWAYS throw an
* error. The caller must use the `watch` method.
*
* @returns {void}
*/
build () {
throw new Error('`build` method not supported. Use `watch` instead.');
}
/**
* Build and then Watch the files.
*
* @see - https://webpack.js.org/api/node/#watching
*
* @returns {Promise}
* Resolves when the watcher has started without an error.
* Rejects when the watcher encounters an error (NOT a stats error).
*/
watch () {
return new Promise((resolve, reject) => {
this.watching = this.compiler.watch(this.watchOptions, (error, stats) => {
if (error) {
this.handleBuildError(error);
reject(error);
return;
}
resolve();
});
});
}
/**
* Stop the watcher.
*
* @returns {Promise}
* Resolves when the watcher has been stopped / closed.
* Rejects never.
*/
stop () {
if (!this.watching) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
this.watching.close(() => {
// Note an error being passed to this callback is not documented in
// webpack's documentation
this.watching = null;
resolve();
});
});
}
/**
* To be called when the WatchCompiler is no longer needed.
*
* Stops the watcher, the compile timer, and dereferences the compiler.
*
* @returns {Promise}
* Resolves when all async destruction logic finishes
*/
destroy () {
super.destroy();
return this.stop();
}
};