From 0e9aa031d3779c7fab9833dad7afffba821cb293 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 11 Jun 2026 10:13:13 +0000 Subject: [PATCH] Simplify changeset entries to 1-2 sentences https://claude.ai/code/session_01XTCdcrC6J6Z7QGr2T9daob --- .changeset/ebusy-retries.md | 19 +------------ .changeset/perf-ignored-reduceplan.md | 8 +----- .changeset/silence-permission-scan-errors.md | 30 +------------------- .changeset/symlink-cycle-guard.md | 22 +------------- 4 files changed, 4 insertions(+), 75 deletions(-) diff --git a/.changeset/ebusy-retries.md b/.changeset/ebusy-retries.md index 7b4163e..cd8e432 100644 --- a/.changeset/ebusy-retries.md +++ b/.changeset/ebusy-retries.md @@ -2,21 +2,4 @@ "watchpack": patch --- -fix: retry `fs.lstat` on transient `EBUSY` errors instead of flagging the -file as removed (fixes #223, #44). - -On Windows it is common for anti-virus scanners, indexers or the editor -itself to briefly hold an exclusive handle on a file that has just -changed. Before this change the watcher would receive the `fs.watch` -event, call `lstat`, get back `EBUSY`, and fall through to `setMissing` -— causing a spurious `remove` event and in some cases leaving the -watcher unable to see further changes for that file until the directory -was re-scanned. - -`DirectoryWatcher` now retries `lstat` up to three times (100 ms apart) -before giving up, and does not emit a remove when the only reason the -file could not be stat'd was `EBUSY`. - -The retry count is controlled by the `WATCHPACK_RETRIES` environment -variable (default: `3`; set to `0` or `"false"` to disable retrying and -restore the previous behaviour). +fix: retry `fs.lstat` on transient `EBUSY` errors instead of emitting a spurious `remove` event (fixes #223, #44). The retry count is controlled by the `WATCHPACK_RETRIES` environment variable (default: `3`; set to `0` or `"false"` to disable retrying). diff --git a/.changeset/perf-ignored-reduceplan.md b/.changeset/perf-ignored-reduceplan.md index b171c22..2d142ed 100644 --- a/.changeset/perf-ignored-reduceplan.md +++ b/.changeset/perf-ignored-reduceplan.md @@ -2,10 +2,4 @@ "watchpack": patch --- -perf: skip the path-separator replacement when the input has no backslash -(benchmarks measure ~35–45% less time for `ignored` matchers on POSIX paths), -fast-path single-element `ignored` arrays, and make `reducePlan`'s selection -loop walk only structurally valid candidates with an early exit when the -ideal reduction is found (measured ~20–40% faster on medium and large -plans). Adds a tinybench suite under `bench/` and a CodSpeed GitHub Actions -workflow so future regressions are caught automatically. +perf: speed up `ignored` matchers (~35–45% faster on POSIX paths) and `reducePlan` (~20–40% faster on medium and large plans). Also adds a tinybench suite under `bench/` and a CodSpeed GitHub Actions workflow to catch future regressions. diff --git a/.changeset/silence-permission-scan-errors.md b/.changeset/silence-permission-scan-errors.md index 8b36787..ae98050 100644 --- a/.changeset/silence-permission-scan-errors.md +++ b/.changeset/silence-permission-scan-errors.md @@ -2,32 +2,4 @@ "watchpack": patch --- -fix: don't log "Watchpack Error (initial scan)" for unreadable entries -inside a watched parent directory (fixes #187). - -Webpack registers every ancestor of a watched file as a watched -directory (so `/mnt/c/Users/me/proj` causes watchpack to scan `/mnt/c`, -`/mnt`, `/`). When such a parent contains entries the current process -can't `lstat` — `pagefile.sys` / `hiberfil.sys` on WSL, `/efi` on Linux -when the EFI partition isn't mounted, protected paths on Node ≥22.17 on -Windows where libuv now reports `EINVAL` instead of `EACCES` — the -initial scan would print: - - Watchpack Error (initial scan): Error: EACCES: permission denied, lstat '/mnt/c/pagefile.sys' - Watchpack Error (initial scan): Error: EINVAL: invalid argument, lstat 'C:\\hiberfil.sys' - Watchpack Error (initial scan): Error: ENODEV: no such device, lstat '/efi' - -These entries aren't actually being watched (only their sibling, e.g. -`/mnt/c/Users`, is) so the log was harmless but very noisy and sent a -lot of users on wild goose chases. - -`DirectoryWatcher#doScan` now treats `EACCES` / `ENODEV` (and `EINVAL` -on Windows) the same way it already treats `EPERM` / `ENOENT` / -`EBUSY`: the offending entry is recorded as missing and the scan -continues silently. The same set is applied to the `readdir` error path -on the watched directory itself, so an unreadable mount point is -treated as removed instead of logged. - -No public API change. If you were relying on the error appearing on -stderr, set the impacted entry up as an explicit watch so a real failure -on it surfaces through the existing `error` event instead. +fix: don't log "Watchpack Error (initial scan)" for unreadable entries inside a watched parent directory, e.g. `pagefile.sys` on WSL or `/efi` on Linux (fixes #187). `EACCES` / `ENODEV` (and `EINVAL` on Windows) errors are now handled like `EPERM` / `ENOENT` / `EBUSY`: the entry is recorded as missing and the scan continues silently. diff --git a/.changeset/symlink-cycle-guard.md b/.changeset/symlink-cycle-guard.md index 862d348..75cfd1c 100644 --- a/.changeset/symlink-cycle-guard.md +++ b/.changeset/symlink-cycle-guard.md @@ -2,24 +2,4 @@ "watchpack": patch --- -fix: prevent unbounded watcher growth when a symlinked directory points -back to one of its own ancestors (cycle protection for the -`followSymlinks: true` symlink-descent path). - -The recent fixes for #190 / #231 made `DirectoryWatcher` follow -symlinked directories whose realpath lives outside the watched real -directory, registering them as nested watched directories. That logic -short-circuits when the symlink target is a sibling in the same parent -(`dirname(realPath) === this.path`), but it does not catch the case -where the target is an _ancestor_ of the symlink itself — for example -`a/b/loop -> ..`. In that case `readdir` followed the symlink, found -the original tree again, and a new `DirectoryWatcher` was created at -each recursion level until the path exceeded `PATH_MAX` (locally -observed: ~1500 watchers within 2 s, ~2500 within 2.5 s). - -`DirectoryWatcher` now computes `path.relative(realPath, itemPath)` -before descending; if the relative path doesn't start with `..` and -isn't absolute (i.e. the symlink target is at-or-above the symlink in -the directory tree), the symlink is recorded as a plain entry instead -of being descended into. Behaviour for symlinks pointing outside the -watched tree (the case #231 fixes) is unchanged. +fix: prevent unbounded watcher growth when a symlinked directory points back to one of its own ancestors (e.g. `a/b/loop -> ..`) with `followSymlinks: true`. Such symlinks are now recorded as plain entries instead of being descended into; symlinks pointing outside the watched tree (#231) behave as before.