Skip to content

fix: give a path watched with other casing the time info of its file on case-insensitive file systems - #358

Merged
alexander-akait merged 7 commits into
mainfrom
fix/case-insensitive-time-info
Oct 16, 2026
Merged

alexander-akait merged 7 commits into
mainfrom
fix/case-insensitive-time-info

Conversation

@alexander-akait

@alexander-akait alexander-akait commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Fixes #228. Supersedes #229.

On macOS and Windows, import B from "./B" resolves when the file is b.js, and webpack watches .../B.js. watchpack already sends change events to that watcher, because watchers are keyed without case. But collectTimeInfoEntries only matches exact case, so B.js gets null ("missing"). webpack stores that null in the module's snapshot, and on the next edit null === null looks unchanged. The first edit rebuilds and later ones don't.

Fix: a watched path that is missing from files, but matches a file there apart from case, gets that file's entry. This happens only on a case-insensitive file system. Whether the directory ignores case is learned once, the first time such a mismatch occurs: lstat both names and compare inode and device. On Linux the other-case name fails to lstat, so it stays null. Missing dependencies (resolution candidates) are therefore never reported as existing, which is the problem with #229's unconditional lowercase match.

Behaviour change: after a case-only rename (hello.txt → hEllO.txt), a watcher for hello.txt now gets the renamed file's entry instead of null. On a case-insensitive file system that name still opens the file. Reporting null caused the same stale-snapshot bug. The existing casing test is updated to match.

Verified in CI (temporary jobs, since removed)

webpack in watch mode, importing ./B for b.js and editing it 3 times:

watchpack macOS outputs Windows outputs
main v0, v1, v1 ❌ v0, v0, v0, v0 ❌
this PR v0, v1, v2, v3 ✅ v0, v0, v1, v2, v3 ✅

webpack's WatchTestCases, WatchCacheUnaffectedTestCases and watch unit tests with this lib: 5,232 passed on Linux, passed on Windows, 5,231 passed on macOS. The single macOS failure, NodeWatchFileSystem › shares one watcher pool between equal options (expects 1 directory watcher, gets 8), fails the same way with the published watchpack 2.6.1. It comes from macOS watching parent directories, and webpack runs its unit tests on Linux only.

Tests

  • A new casing test (it runs where the file system ignores case: macOS and Windows CI): a file watched as A while a exists gets a's entry, and the entry follows edits.
  • A new case-sensitive test (Linux): A stays null.
  • Full suite 206/206 locally, lint clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_017TkBWTk3wcyUcJYDp5ZhaP

Summary by CodeRabbit

  • Bug Fixes
    • Fixed file watching on case-insensitive file systems when a file is referenced with different capitalization. File changes are now detected consistently, so rebuilds continue after the first change.

@changeset-bot

changeset-bot Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1be3435

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
watchpack Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codspeed

codspeed Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ 1 benchmark spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

✅ 36 untouched benchmarks


Comparing fix/case-insensitive-time-info (1be3435) with main (6695b9f)

Open in CodSpeed

@codecov

codecov Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.29630% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 92.65%. Comparing base (6695b9f) to head (1be3435).

Files with missing lines Patch % Lines
lib/DirectoryWatcher.js 96.29% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #358      +/-   ##
==========================================
+ Coverage   92.58%   92.65%   +0.06%     
==========================================
  Files           8        8              
  Lines        1363     1389      +26     
  Branches      405      416      +11     
==========================================
+ Hits         1262     1287      +25     
- Misses         95       96       +1     
  Partials        6        6              
Flag Coverage Δ
integration 92.65% <96.29%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@alexander-akait
alexander-akait marked this pull request as ready for review October 16, 2026 03:57
@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b8416e30-7b6f-42a3-8819-e3987e77ae3a
📥 Commits

Reviewing files that changed from the base of the PR and between 36454df and 1be3435.

📒 Files selected for processing: 2
  • lib/DirectoryWatcher.js
  • test/DirectoryWatcherExtra.test.js
🚧 Files skipped from review as they are similar to previous changes: 1
  • lib/DirectoryWatcher.js

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.

Walkthrough

DirectoryWatcher now tracks whether its directory is case-sensitive. When a watched path is absent from the timestamp map, it checks whether a differently cased tracked path identifies the same file. If the filesystem is case-insensitive, it uses that path’s time-info entry. Tests cover timestamp updates on case-insensitive filesystems, missing paths on case-sensitive filesystems, and deferred detection after a stat error. The change also adds type declarations and a patch changeset.

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 1be34

The change gives differently cased watched paths the time info of their file on case-insensitive file systems. A transient stat error now defers detection instead of fixing the wrong result. No merge-blocking risk is identified.

Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main fix for differently cased paths on case-insensitive file systems.
Linked Issues check Passed PASS. The changes address issue [#228]. DirectoryWatcher matches a missing watched path to a file with different casing only after lstat checks establish a case-insensitive file system. The case-s…
Out of Scope Changes check Passed PASS. The changes stay within issue [#228]. The implementation, declaration updates, regression tests, transient-error coverage, and changeset support case-aware time-info collection and its rebuild b…
Docstring Coverage Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 4…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5d7acb11-4235-43fc-916a-09be09662114
📥 Commits

Reviewing files that changed from the base of the PR and between 6695b9f and 36454df.

📒 Files selected for processing: 4
  • .changeset/case-insensitive-time-info.md
  • lib/DirectoryWatcher.js
  • test/Casing.test.js
  • types/DirectoryWatcher.d.ts

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

Comment thread lib/DirectoryWatcher.js
@alexander-akait
alexander-akait merged commit 0418015 into main Oct 16, 2026
51 checks passed
@alexander-akait
alexander-akait deleted the fix/case-insensitive-time-info branch October 16, 2026 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

collectTimeInfoEntries does not consider case-sensitivity initially

1 participant