diff --git a/lib/index.js b/lib/index.js index b4ecea6..3592f7f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,6 +3,7 @@ const filewatcher = require('filewatcher'); const { join } = require('path'); const semver = require('semver'); const { pathToFileURL } = require('url'); +const debounceFn = require('debounce'); const { clearFactory } = require('./clear'); const { configureDeps, configureIgnore } = require('./ignore'); @@ -58,26 +59,29 @@ module.exports = function ( // Run ./dedupe.js as preload script if (dedupe) process.env.NODE_DEV_PRELOAD = localPath('dedupe'); - const watcher = filewatcher({ debounce, forcePolling, interval }); + const watcher = filewatcher({ forcePolling, interval }); let isPaused = false; // The child_process let child; - watcher.on('change', file => { - clearOutput(); - notify('Restarting', `${file} has been modified`); - watcher.removeAll(); - isPaused = true; - if (child) { - // Child is still running, restart upon exit - child.on('exit', start); - stop(); - } else { - // Child is already stopped, probably due to a previous error - start(); - } - }); + watcher.on( + 'change', + debounceFn(file => { + clearOutput(); + notify('Restarting', `${file} has been modified`); + watcher.removeAll(); + isPaused = true; + if (child) { + // Child is still running, restart upon exit + child.on('exit', start); + stop(); + } else { + // Child is already stopped, probably due to a previous error + start(); + } + }, debounce) + ); watcher.on('fallback', limit => { log.warn('node-dev ran out of file handles after watching %s files.', limit); diff --git a/package.json b/package.json index 96afe80..6149937 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ }, "dependencies": { "dateformat": "^3.0.3", + "debounce": "^1.2.1", "dynamic-dedupe": "^0.3.0", "filewatcher": "~3.0.0", "get-package-type": "^0.1.0", diff --git a/test/spawn/debounce-multi-file.js b/test/spawn/debounce-multi-file.js new file mode 100644 index 0000000..6f41d64 --- /dev/null +++ b/test/spawn/debounce-multi-file.js @@ -0,0 +1,25 @@ +const tap = require('tap'); + +const { spawn, touchFile } = require('../utils'); + +tap.test('should reset debounce timer if a different file changes', t => { + spawn('--debounce=1000 --interval=50 server.js', out => { + if (out.match(/touch message.js/)) { + const ts = Date.now(); + touchFile('server.js'); + for (let i = 0; i <= 2000; i += 500) { + setTimeout(() => { + touchFile('message.js'); + }, i); + } + return out2 => { + if (out2.match(/Restarting/)) { + if (Date.now() - ts < 2500) { + t.fail('Debounce logic did not wait 200 ms after the second change.'); + } + return { exit: t.end.bind(t) }; + } + }; + } + }); +});