From 4721a8684c57027e5297cd66e785bd3133630ae2 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Sat, 14 Jan 2023 19:04:25 +0100 Subject: [PATCH 1/5] Implement fix for Fast Refresh bug --- lib/DirectoryWatcher.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/DirectoryWatcher.js b/lib/DirectoryWatcher.js index abbb142..cc28b6d 100644 --- a/lib/DirectoryWatcher.js +++ b/lib/DirectoryWatcher.js @@ -738,7 +738,19 @@ class DirectoryWatcher extends EventEmitter { for (const watcher of watchers) { const path = watcher.path; if (!fileTimestamps.has(path)) { - fileTimestamps.set(path, null); + let lowercase = withoutCase(path) + if (this.filesWithoutCase.has(withoutCase(path))) { + const keys = (fileTimestamps).keys(); + let nextKey = null; + while (!(nextKey = keys.next()).done) { + if (nextKey.value.toLowerCase() === lowercase) { + fileTimestamps.set(path, fileTimestamps.get(nextKey.value)) + break; + } + } + } else { + fileTimestamps.set(path, null); + } } } } From 8dce1439072f99a27d5c09db2f69e054199e04e1 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Sat, 14 Jan 2023 19:07:29 +0100 Subject: [PATCH 2/5] Update DirectoryWatcher.js --- lib/DirectoryWatcher.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/DirectoryWatcher.js b/lib/DirectoryWatcher.js index cc28b6d..484d3a3 100644 --- a/lib/DirectoryWatcher.js +++ b/lib/DirectoryWatcher.js @@ -738,9 +738,14 @@ class DirectoryWatcher extends EventEmitter { for (const watcher of watchers) { const path = watcher.path; if (!fileTimestamps.has(path)) { + // If the file does not exist, we'll mark it as null, + // but beforehand we check if the same file with different + // casing exists in the map. + + // This can happen because the `this.files` map is case-sensitive. let lowercase = withoutCase(path) - if (this.filesWithoutCase.has(withoutCase(path))) { - const keys = (fileTimestamps).keys(); + if (this.filesWithoutCase.has(lowercase)) { + const keys = fileTimestamps.keys(); let nextKey = null; while (!(nextKey = keys.next()).done) { if (nextKey.value.toLowerCase() === lowercase) { @@ -748,9 +753,12 @@ class DirectoryWatcher extends EventEmitter { break; } } - } else { - fileTimestamps.set(path, null); } + + // If no file with different casing was found, we'll mark it as null + if (!fileTimestamps.has(path)) { + fileTimestamps.set(path, null); + } } } } From 3aa6c562f420d2df5463ada32fa2dc18d471c19b Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Sun, 15 Jan 2023 19:15:53 +0100 Subject: [PATCH 3/5] styles --- lib/DirectoryWatcher.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/DirectoryWatcher.js b/lib/DirectoryWatcher.js index 484d3a3..1030fd2 100644 --- a/lib/DirectoryWatcher.js +++ b/lib/DirectoryWatcher.js @@ -743,13 +743,13 @@ class DirectoryWatcher extends EventEmitter { // casing exists in the map. // This can happen because the `this.files` map is case-sensitive. - let lowercase = withoutCase(path) + let lowercase = withoutCase(path); if (this.filesWithoutCase.has(lowercase)) { const keys = fileTimestamps.keys(); let nextKey = null; while (!(nextKey = keys.next()).done) { if (nextKey.value.toLowerCase() === lowercase) { - fileTimestamps.set(path, fileTimestamps.get(nextKey.value)) + fileTimestamps.set(path, fileTimestamps.get(nextKey.value)); break; } } @@ -758,7 +758,7 @@ class DirectoryWatcher extends EventEmitter { // If no file with different casing was found, we'll mark it as null if (!fileTimestamps.has(path)) { fileTimestamps.set(path, null); - } + } } } } From a164f67b9bde149802363905a50bd44d24ce1282 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Sun, 15 Jan 2023 19:24:10 +0100 Subject: [PATCH 4/5] add a test --- test/DirectoryWatcher.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/DirectoryWatcher.js b/test/DirectoryWatcher.js index 8b8072d..12d86b1 100644 --- a/test/DirectoryWatcher.js +++ b/test/DirectoryWatcher.js @@ -169,6 +169,32 @@ describe("DirectoryWatcher", function() { }); }); + it("should collectTimeInfoEntries for uppercase and lowercase filename", function(done) { + testHelper.file("A"); + var d = new DirectoryWatcher(fixtures, {}); + var a = d.watch(path.join(fixtures, "a")); + + let filenameTimestamps = new Map(); + let directoryTimestamps = new Map(); + testHelper.tick(function() { + d.collectTimeInfoEntries(filenameTimestamps, directoryTimestamps); + let lowercase = filenameTimestamps.get( + path.join(testHelper.testdir, "a") + ); + let uppercase = filenameTimestamps.get( + path.join(testHelper.testdir, "A") + ); + if (!lowercase) { + throw new Error("should have timeInfoEntries for lowercase"); + } + if (!uppercase) { + throw new Error("should have timeInfoEntries for uppercase"); + } + a.close(); + done(); + }); + }); + if (!+process.env.WATCHPACK_POLLING) { it("should log errors emitted from watcher to stderr", function(done) { var error_logged = false; From 44dcc0f1db23cad3a484b4ffd01ca19d588386d6 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Sun, 15 Jan 2023 19:49:41 +0100 Subject: [PATCH 5/5] only run test when it is case-sensitive file system --- test/DirectoryWatcher.js | 57 ++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/test/DirectoryWatcher.js b/test/DirectoryWatcher.js index 12d86b1..b6b60cc 100644 --- a/test/DirectoryWatcher.js +++ b/test/DirectoryWatcher.js @@ -12,6 +12,15 @@ var testHelper = new TestHelper(fixtures); var openWatchers = []; +var fsIsCaseInsensitive; +try { + fsIsCaseInsensitive = require("fs").existsSync( + path.join(__dirname, "..", "PACKAGE.JSON") + ); +} catch (e) { + fsIsCaseInsensitive = false; +} + var DirectoryWatcher = function(p, options) { var d = new OrgDirectoryWatcher(getWatcherManager(options), p, options); openWatchers.push(d); @@ -169,31 +178,33 @@ describe("DirectoryWatcher", function() { }); }); - it("should collectTimeInfoEntries for uppercase and lowercase filename", function(done) { - testHelper.file("A"); - var d = new DirectoryWatcher(fixtures, {}); - var a = d.watch(path.join(fixtures, "a")); + if (fsIsCaseInsensitive) { + it("should collectTimeInfoEntries for uppercase and lowercase filename", function(done) { + testHelper.file("A"); + var d = new DirectoryWatcher(fixtures, {}); + var a = d.watch(path.join(fixtures, "a")); - let filenameTimestamps = new Map(); - let directoryTimestamps = new Map(); - testHelper.tick(function() { - d.collectTimeInfoEntries(filenameTimestamps, directoryTimestamps); - let lowercase = filenameTimestamps.get( - path.join(testHelper.testdir, "a") - ); - let uppercase = filenameTimestamps.get( - path.join(testHelper.testdir, "A") - ); - if (!lowercase) { - throw new Error("should have timeInfoEntries for lowercase"); - } - if (!uppercase) { - throw new Error("should have timeInfoEntries for uppercase"); - } - a.close(); - done(); + let filenameTimestamps = new Map(); + let directoryTimestamps = new Map(); + testHelper.tick(function() { + d.collectTimeInfoEntries(filenameTimestamps, directoryTimestamps); + let lowercase = filenameTimestamps.get( + path.join(testHelper.testdir, "a") + ); + let uppercase = filenameTimestamps.get( + path.join(testHelper.testdir, "A") + ); + if (!lowercase) { + throw new Error("should have timeInfoEntries for lowercase"); + } + if (!uppercase) { + throw new Error("should have timeInfoEntries for uppercase"); + } + a.close(); + done(); + }); }); - }); + } if (!+process.env.WATCHPACK_POLLING) { it("should log errors emitted from watcher to stderr", function(done) {