Ensure @source files behind symlinks trigger rebuilds in @tailwindcss/vite#20347
Ensure @source files behind symlinks trigger rebuilds in @tailwindcss/vite#20347Nic-Polumeyv wants to merge 2 commits into
@source files behind symlinks trigger rebuilds in @tailwindcss/vite#20347Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
WalkthroughThe Vite plugin now caches resolved real paths for scanned files, watches both symlinked and resolved source paths, and matches file changes using either path form. A new integration test covers rebuilding when a workspace package’s real source file changes through a 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/@tailwindcss-vite/src/index.ts (1)
539-549: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueConsider comparing the real path of the scanned file with the real path of the changed file.
To guarantee robustness in complex workspace topologies (e.g. where multiple symlinks point to the same physical file and Vite reports a different symlink than the one scanned), consider explicitly comparing their resolved real paths as a final fallback.
💡 Proposed refactor
isScannedFile(file: string, realpath: string | null): boolean { for (let scanned of this.scannedFiles) { if (scanned === file) return true if (realpath !== null && scanned === realpath) return true - if (this.realpath(scanned) === file) return true + + let scannedReal = this.realpath(scanned) + if (scannedReal === file) return true + if (realpath !== null && scannedReal === realpath) return true } return false }
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 6ae12ef6-df9f-412b-97e6-6c5b02e0a68f
📒 Files selected for processing (3)
CHANGELOG.mdintegrations/vite/index.test.tspackages/@tailwindcss-vite/src/index.ts
Confidence Score: 5/5Safe to merge — the change is narrowly scoped to symlink resolution in the Vite plugin and is covered by a new integration test that reproduces the exact failure scenario. The change adds a lazily-populated, per-rebuild cache of real paths, registers both the symlinked and real paths with Vite's watcher, and extends isScannedFile to compare against both sides. All code paths fall back gracefully on realpathSync errors, the cache is cleared on full rebuilds to handle symlink retargeting, and the duplicate-glob-base case is handled correctly with a Set. No existing logic is removed, only extended. No files require special attention. Reviews (2): Last reviewed commit: "Clear resolved path cache on full rebuil..." | Re-trigger Greptile |
|
Testing this a bit further, the same class shows up in the scanner's other consumers. The CLI's native
Happy to fix the CLI the same way in a follow-up, though canonicalizing once in |
Fixes #20346
Summary
Since #20203 the scanner preserves symlinks in
@sourcepaths, soscanner.filescan contain a path likeapp/node_modules/pkg/index.jswhile Vite tracks the module and its file change events under the realpackages/pkg/index.js. The plugin registered only the written path viaaddWatchFile, which Vite's watcher ignores insidenode_modules, so editing the real file behind a workspace symlink never invalidated the CSS module and new candidates only appeared after restarting the dev server.This registers the resolved path alongside the written one for scanned files and glob bases, cached per root.
isScannedFilegets the missing direction too: it already resolved the changed file before comparing against scanned paths, now it also resolves scanned paths before comparing against the changed file, so full reloads for non-module@sourcefiles keep working when the path goes through a symlink.Test plan
Added an integration test with a pnpm workspace where
@sourcepoints through thenode_modulessymlink of a linked workspace package. It fails without the change (the new candidate never appears until the dev server restarts) and passes with it. The fullintegrations/vitesuite passes. Also verified the reproduction from #20346 directly: with this build, editing the file behind the symlink updates the page without a restart.