From 923cb9dbf1ffa8bf1ce05d55af4faa5ab866b4ab Mon Sep 17 00:00:00 2001 From: Dobes Vandermeer Date: Tue, 5 Sep 2023 21:21:30 -0700 Subject: [PATCH 1/3] Implement a global change debounce --- lib/index.js | 32 ++++++++++++++++++-------------- package.json | 1 + 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/index.js b/lib/index.js index b4ecea6..a9eccb5 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'); @@ -64,20 +65,23 @@ module.exports = function ( // 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", From 80b77c280d089b2aa1e895f92782b424d58aeec3 Mon Sep 17 00:00:00 2001 From: Dobes Vandermeer Date: Sat, 9 Sep 2023 00:10:14 -0700 Subject: [PATCH 2/3] Don't double-debounce with watcher library --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index a9eccb5..3592f7f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -59,7 +59,7 @@ 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 From 90d965e164c630e9d85076abb72385c36001a9b1 Mon Sep 17 00:00:00 2001 From: Dobes Vandermeer Date: Sat, 9 Sep 2023 00:10:31 -0700 Subject: [PATCH 3/3] Add a test for the global debounce --- test/spawn/debounce-multi-file.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 test/spawn/debounce-multi-file.js 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) }; + } + }; + } + }); +});