[PR #1014] [MERGED] fix(dev): avoid app reloads for colocated files #1016

Closed
opened 2026-05-06 13:11:35 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/1014
Author: @NathanDrake2406
Created: 5/2/2026
Status: Merged
Merged: 5/2/2026
Merged by: @james-elicx

Base: mainHead: nathan/app-watcher-route-files


📝 Commits (1)

  • 1d72b85 fix(dev): avoid app reloads for colocated files

📊 Changes

4 files changed (+149 additions, -10 deletions)

View changed files

📝 packages/vinext/src/index.ts (+12 -9)
packages/vinext/src/server/dev-route-files.ts (+94 -0)
📝 packages/vinext/src/server/metadata-routes.ts (+1 -1)
📝 tests/file-matcher.test.ts (+42 -0)

📄 Description

What this changes

Stops the App Router dev watcher from invalidating the generated route entry and sending a full reload when ordinary colocated files are added or removed under app/, such as app/components/Button.tsx.

The watcher now invalidates only files that can affect App Router structure or generated metadata route entries: route conventions such as page, route, layout, template, loading, error, access fallback files, root global-error, and vinext metadata route files.

Fixes #1013.

Why

Next.js explicitly treats arbitrary project files in app/ as safely colocated and non-routable. The source backs that up in the route discovery matcher:

vinext was using only the broad page extension regex for app/ watcher add/unlink events, so any .ts, .tsx, .js, or .jsx file under app/ looked route-affecting and triggered a full reload.

Approach

Add a small pure predicate, shouldInvalidateAppRouteFile, that mirrors vinext's current App Router and metadata discovery boundaries:

  • rejects files outside the exact app/ directory, fixing sibling-prefix cases like app-utils/
  • rejects private _ folders
  • accepts App Router structure conventions that change the generated route tree or RSC entry wiring
  • accepts vinext's dynamic and static metadata route files using the existing metadata route map

The watcher still keeps the broad extension behavior for the Pages Router, since every matching file under pages/ is routable by design unless filtered elsewhere.

Validation

  • vp test run tests/file-matcher.test.ts
  • vp test run tests/file-matcher.test.ts tests/page-extensions-routing.test.ts
  • vp check tests/file-matcher.test.ts packages/vinext/src/server/dev-route-files.ts packages/vinext/src/index.ts packages/vinext/src/server/metadata-routes.ts
  • vp run vinext#build

The package build completed successfully with the existing virtual-module externalization warnings for private-next-instrumentation-client, virtual:vinext-rsc-entry, and virtual:vite-rsc/client-references.

Risks / follow-ups

The metadata side intentionally follows vinext's current scanMetadataFiles behavior, not every future Next.js metadata convention. If vinext expands metadata route support later, this predicate should be updated with the same source of truth.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/1014 **Author:** [@NathanDrake2406](https://github.com/NathanDrake2406) **Created:** 5/2/2026 **Status:** ✅ Merged **Merged:** 5/2/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `nathan/app-watcher-route-files` --- ### 📝 Commits (1) - [`1d72b85`](https://github.com/cloudflare/vinext/commit/1d72b85dd2b9cd2fb042594a393cc48475375414) fix(dev): avoid app reloads for colocated files ### 📊 Changes **4 files changed** (+149 additions, -10 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/index.ts` (+12 -9) ➕ `packages/vinext/src/server/dev-route-files.ts` (+94 -0) 📝 `packages/vinext/src/server/metadata-routes.ts` (+1 -1) 📝 `tests/file-matcher.test.ts` (+42 -0) </details> ### 📄 Description ## What this changes Stops the App Router dev watcher from invalidating the generated route entry and sending a full reload when ordinary colocated files are added or removed under `app/`, such as `app/components/Button.tsx`. The watcher now invalidates only files that can affect App Router structure or generated metadata route entries: route conventions such as `page`, `route`, `layout`, `template`, `loading`, `error`, access fallback files, root `global-error`, and vinext metadata route files. Fixes #1013. ## Why Next.js explicitly treats arbitrary project files in `app/` as safely colocated and non-routable. The source backs that up in the route discovery matcher: - [`createValidFileMatcher` builds leaf-only app route matchers](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/find-page-file.ts#L79-L172) - [Next.js dev bundler skips non-app-router page files after handling layouts/root not-found](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts#L619-L679) - [Build route discovery filters app files through the app router page/layout/default/root-not-found predicates](https://github.com/vercel/next.js/blob/canary/packages/next/src/build/route-discovery.ts#L86-L116) vinext was using only the broad page extension regex for `app/` watcher add/unlink events, so any `.ts`, `.tsx`, `.js`, or `.jsx` file under `app/` looked route-affecting and triggered a full reload. ## Approach Add a small pure predicate, `shouldInvalidateAppRouteFile`, that mirrors vinext's current App Router and metadata discovery boundaries: - rejects files outside the exact `app/` directory, fixing sibling-prefix cases like `app-utils/` - rejects private `_` folders - accepts App Router structure conventions that change the generated route tree or RSC entry wiring - accepts vinext's dynamic and static metadata route files using the existing metadata route map The watcher still keeps the broad extension behavior for the Pages Router, since every matching file under `pages/` is routable by design unless filtered elsewhere. ## Validation - `vp test run tests/file-matcher.test.ts` - `vp test run tests/file-matcher.test.ts tests/page-extensions-routing.test.ts` - `vp check tests/file-matcher.test.ts packages/vinext/src/server/dev-route-files.ts packages/vinext/src/index.ts packages/vinext/src/server/metadata-routes.ts` - `vp run vinext#build` The package build completed successfully with the existing virtual-module externalization warnings for `private-next-instrumentation-client`, `virtual:vinext-rsc-entry`, and `virtual:vite-rsc/client-references`. ## Risks / follow-ups The metadata side intentionally follows vinext's current `scanMetadataFiles` behavior, not every future Next.js metadata convention. If vinext expands metadata route support later, this predicate should be updated with the same source of truth. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:11:35 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#1016
No description provided.