mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[GH-ISSUE #1013] adding any .ts/.tsx file inside app/ triggers a full page reload — watcher uses broad extension regex instead of route-file regex #227
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#227
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @eashish93 on GitHub (May 2, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/1013
Summary
The dev-server file watcher fires
invalidateAppRouteCache()+hot.send({ type: "full-reload" })for any.ts/.tsx/.jsx/.jsfile added (or removed) underapp/, including co-located components, helpers, types, and other non-route files. Next.js explicitly supports co-locating non-route files insideapp/(docs) — only specific filenames (page,route,layout,default,template,loading,error,not-found) are routes.Effect: every
app/components/Button.tsx,app/_lib/helpers.ts, etc. that you create during development triggers a full page hard-refresh instead of HMR. This is especially painful for AI-driven scaffolding flows that create many co-located files in quick succession — the user sees the app constantly hard-reload mid-iteration.Reproduce
Minimal vinext app with App Router. With dev server running:
Compared to the normal HMR path:
The route-relevant case works:
The bug is that any other file in
app/produces the same full reload as a real route addition.Root cause
dist/index.js:911-921(compiled fromsrc/index.ts) uses the broad extension regex:pageExtensions.test(filePath)is true for any.ts/.tsxfile, regardless of whether its basename matches a route filename. Addingapp/components/Button.tsxinvalidates the App Router route cache and forces a full reload.The kicker:
dist/routing/file-matcher.jsalready exports the correct regex right next toextensionRegex:These specifically match
(^|/)page.tsx,(^|/)layout.tsx, etc. The watcher just isn't using them.There's also a likely-similar issue at
dist/index.js:877in thehotUpdatehandler for the pages router:Same broad check, same shape — non-route files in
pages/(if anyone co-locates) would full-reload too.Proposed fix
Use the already-exported route-file regex set, and only invalidate the route cache + full-reload when the filename actually corresponds to a routing file. App Router route files:
page.*,route.*,layout.*,default.*,template.*,loading.*,error.*,not-found.*,forbidden.*,unauthorized.*,global-error.*, plus themiddleware.*andinstrumentation.*at the project root.Suggested shape (sketch):
Two micro-improvements bundled in:
path.septo the prefix check (appDir + path.sep) so a sibling likeapp-utils/doesn't accidentally matchappDir = "/proj/app".app/; keep the broadpageExtensionsforpages/since the Pages Router treats every.tsxunderpages/as a route by design.Environment