Skip to content

Instantly share code, notes, and snippets.

@vladkosinov
Created August 15, 2016 12:36
Show Gist options
  • Save vladkosinov/93b7e4002e18877d02d8d23313ef73ea to your computer and use it in GitHub Desktop.
Save vladkosinov/93b7e4002e18877d02d8d23313ef73ea to your computer and use it in GitHub Desktop.
webpack-nodemon-middleware.js
const nodemon = require('nodemon');
const chalk = require('chalk');
const defaultNodemonOptions = {
execMap: { js: 'node' },
runOnChangeOnly: true,
ext: 'noop',
watch: ['noop/'],
ignore: ['*'],
stdout: false,
stderr: false
};
const logPrefix = chalk.green('[webpack-nodemon-middleware]');
function log(...args) {
console.log(...args);
}
module.exports = function createWebpackNodemonMiddleware(compiler, options) {
const nodemonConfig = Object.assign({}, defaultNodemonOptions, options.nodemon);
const readyMessage = options.readyMessage;
const beforeRestart = options.beforeRestart || ((f) => f());
const restartTimeout = options.restartTimeout || 200;
const statsConfig = options.stats || {};
const demon = nodemon(nodemonConfig);
let bundleIsValid = false;
let processIsOnline = false;
let listeners = [];
let restartTimeoutId = null;
function restart() {
beforeRestart(() => {
if (restartTimeoutId !== null) {
clearTimeout(restartTimeoutId);
}
restartTimeoutId = setTimeout(() => {
restartTimeoutId = null;
demon.restart();
}, restartTimeout);
});
}
function notifyListeners() {
const cbs = listeners;
listeners = [];
if (cbs.length) {
log(logPrefix, `continue delayed requests (${cbs.length})`);
}
cbs.forEach(cb => cb());
}
demon
.on('restart', () => {
processIsOnline = false;
log(logPrefix, 'process is offline');
})
.on('stdout', (stdout) => {
log(logPrefix, 'stdout:');
log(stdout.toString().trim());
const includes = stdout.toString().includes(readyMessage);
if (!includes) { return; }
if (!bundleIsValid) { return; }
processIsOnline = true;
log(logPrefix, 'process is online');
notifyListeners();
})
.on('stderr', (stderr) => {
log(logPrefix, 'stderr:', stderr.toString());
});
compiler.plugin('done', (stats) => {
bundleIsValid = true;
log(logPrefix, 'bundle:');
log(stats.toString(statsConfig));
restart();
});
function invalidPlugin() {
if (bundleIsValid) {
log(logPrefix, 'bundle in now INVALID');
}
bundleIsValid = false;
}
function invalidAsyncPlugin(c, cb) {
invalidPlugin();
cb();
}
compiler.plugin('invalid', invalidPlugin);
compiler.plugin('watch-run', invalidAsyncPlugin);
compiler.plugin('run', invalidAsyncPlugin);
compiler.watch({}, (err) => {
if (err) {
throw err;
}
});
function callOnServerReady(cb) {
if (bundleIsValid && processIsOnline) {
return cb();
}
log(logPrefix, 'request delayed until process restarted');
listeners.push(cb);
return null;
}
function webpackNodemonMiddleware(req, res, next) {
callOnServerReady(err => next(err));
}
webpackNodemonMiddleware.restart = restart;
return webpackNodemonMiddleware;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment