fix: restore full page reload for watched external files on Vite 7.1+#19670
fix: restore full page reload for watched external files on Vite 7.1+#19670Arxsher wants to merge 3 commits intotailwindlabs:mainfrom
Conversation
WalkthroughA new 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. No actionable comments were generated in the recent review. 🎉 Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. 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.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@packages/`@tailwindcss-vite/src/index.ts:
- Around line 98-115: The current handleHotUpdate logic uses
files.includes(path.basename(file)) which can false-positive across different
watched directories; update the check to compare full resolved paths instead —
for the server.watcher.getWatched() loop, replace the basename check with
something like files.some(f => path.resolve(dir, f) === path.resolve(file)) so
the code only matches when the exact watched file path equals the changed file;
keep the rest of handleHotUpdate (including server.moduleGraph.getModulesByFile
and the full-reload payload send) unchanged.
- Around line 104-106: The reload check uses
Array.from(server.watcher.getWatched()) which returns [] because getWatched()
returns a plain object; replace Array.from(...) with
Object.entries(server.watcher.getWatched()) and keep the .some(...) logic over
([dir, files]) to locate the watched directory; also tighten the directory check
in the callback by preventing prefix false-matches—change file.startsWith(dir)
to ensure a directory boundary (e.g., file.startsWith(dir + path.sep) or
comparable check) while still using path.basename(file) to check the file name.
🧹 Nitpick comments (1)
packages/@tailwindcss-vite/src/index.ts (1)
98-115: Consider returning an empty array to suppress duplicate default HMR handling.When
handleHotUpdatedoesn't return a value, Vite continues its default HMR pipeline. For non-module files this is typically harmless, but explicitly returning[](empty modules array) after sending the full-reload makes intent clear and avoids potential double-processing.Suggested change
if (server.hot) { server.hot.send(payload) } else { server.ws.send(payload) } + return [] }
| handleHotUpdate({ server, file }) { | ||
| // If the changed file is being watched by Tailwind but isn't part of the | ||
| // module graph (like a PHP or HTML file), we need to trigger a full | ||
| // reload manually. | ||
| if ( | ||
| !server.moduleGraph.getModulesByFile(file) && | ||
| Array.from(server.watcher.getWatched()).some(([dir, files]) => { | ||
| return file.startsWith(dir) && files.includes(path.basename(file)) | ||
| }) | ||
| ) { | ||
| const payload = { type: 'full-reload' as const, path: '*' } | ||
| if (server.hot) { | ||
| server.hot.send(payload) | ||
| } else { | ||
| server.ws.send(payload) | ||
| } | ||
| } | ||
| }, |
There was a problem hiding this comment.
path.basename match can false-positive across directories.
files.includes(path.basename(file)) only checks the filename, so two different watched directories each containing e.g. index.php would both match. This is minor when the consequence is just a full-reload, but it means reloads fire for unrelated file changes. Consider comparing the full resolved path instead of just the basename.
🤖 Prompt for AI Agents
In `@packages/`@tailwindcss-vite/src/index.ts around lines 98 - 115, The current
handleHotUpdate logic uses files.includes(path.basename(file)) which can
false-positive across different watched directories; update the check to compare
full resolved paths instead — for the server.watcher.getWatched() loop, replace
the basename check with something like files.some(f => path.resolve(dir, f) ===
path.resolve(file)) so the code only matches when the exact watched file path
equals the changed file; keep the rest of handleHotUpdate (including
server.moduleGraph.getModulesByFile and the full-reload payload send) unchanged.
|
Thanks for the cleanup @RobinMalfait, Appreciate the help getting this ready. |
|
@Arxsher thank you for the PR! Just doing a few more tests here and then I think we can get it merged! |
PR: Fix @source file changes not triggering full page reload on Vite 7.1+
Description
This PR addresses issue #19637 where template files (PHP, HTML, Blade, etc.) watched via the
@sourcedirective fail to trigger a full page reload when using Vite 7.1 or newer.Root Cause
Vite 7.1 introduced the Environment API, which supersedes the legacy WebSocket API for HMR. Specifically:
server.ws.sendis deprecated/ignored for certain external file updates in favor ofserver.hot.send.@tailwindcss/viteplugin currently collectsViteDevServerinstances but lacks ahandleHotUpdatehook to explicitly trigger reloads for non-module files added viaaddWatchFile.Changes
handleHotUpdatehook in the@tailwindcss/viteplugin..php,.html) but are watched by Tailwind.full-reloadusing the newserver.hot.sendAPI if available (Vite 7.1+), with a fallback toserver.ws.sendfor backward compatibility.Verification
.phpfile.server.hot.sendrestores the expected reload behavior.