Skip to content

fix(vite): skip early dev handler for special prefixes#3817

Merged
pi0 merged 3 commits intomainfrom
fix/vite-prefixes
Nov 24, 2025
Merged

fix(vite): skip early dev handler for special prefixes#3817
pi0 merged 3 commits intomainfrom
fix/vite-prefixes

Conversation

@pi0
Copy link
Copy Markdown
Member

@pi0 pi0 commented Nov 24, 2025

(from pair programming with @atinux on chat-vue template)

Nitro vite plugin adds an early vite dev middleware to handle SSR/API requests before overlapping with vite's root-level static asset serving.

We skip the early handler for requests with an extension but it is not enough as some plugins such as unplugin-vue-router use /__ virtual prefix and vite-plugin-layouts uses /@ prefix.

This PR skips for these special patterns too.

Note: API routes still work with routes starting with /__ or /@ only if there is a file named like /_test or @foo in root of project, it will be wrongly served.

dev handler for special prefixes
@vercel
Copy link
Copy Markdown

vercel Bot commented Nov 24, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
nitro.build Ready Ready Preview Comment Nov 24, 2025 5:38pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 24, 2025

📝 Walkthrough

Walkthrough

Tightens nitroDevMiddlewarePre routing in src/build/vite/dev.ts: always sets the Vary header, and only delegates to nitroDevMiddleware when the URL has no file extension, the sec-fetch-dest is absent or is document/iframe/frame/empty, and the path does not start with /__ or /@. Added clarifying comments.

Changes

Cohort / File(s) Summary
Middleware invocation logic refinement
src/build/vite/dev.ts
Always set Vary header for the middleware. Replace prior extension-only pre-check with combined conditions: require no file extension in the URL, require absent or browser-like sec-fetch-dest (document/iframe/frame/empty), and exclude paths beginning with /__ or /@. Add explanatory comments clarifying intent to avoid overlapping Vite static assets.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify correctness and ordering of the combined conditional checks (extension detection, sec-fetch-dest values, prefix exclusion).
  • Confirm Vary header placement is appropriate for all request flows.
  • Check for edge cases where legitimate asset or API requests might be excluded or misrouted by the tightened conditions.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title follows conventional commits format with a clear 'fix' type and descriptive subject about skipping early dev handler for special prefixes.
Description check ✅ Passed The description is directly related to the changeset, explaining the context, motivation, and specific problem being addressed in the code changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/vite-prefixes

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Nov 24, 2025

Open in StackBlitz

npm i https://pkg.pr.new/nitrojs/nitro@3817

commit: d0016e0

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/build/vite/dev.ts (1)

253-260: Logic is sound. Consider minor refactors for clarity.

The three-condition check correctly narrows when the Nitro middleware runs, avoiding overlap with Vite's static asset serving. The regex patterns are appropriate for their purposes.

Optional refactor 1: The file extension check could be more readable:

-      // No file extension (/src/index.ts)
-      !req.url!.match(/\.([a-z0-9]+)(?:[?#]|$)/i)?.[1] &&
+      // No file extension (/src/index.ts)
+      !/\.([a-z0-9]+)(?:[?#]|$)/i.test(req.url!) &&

This avoids the optional chaining and is clearer in intent (testing for absence rather than negating a captured group).

Optional refactor 2: The special prefix check has an unnecessary .*:

-      // Special prefixes (/__vue-router/auto-routes, /@vite-plugin-layouts/, etc)
-      !/^\/(?:__|@).*/.test(req.url!)
+      // Special prefixes (/__vue-router/auto-routes, /@vite-plugin-layouts/, etc)
+      !/^\/(?:__|@)/.test(req.url!)

The .* doesn't affect the match since we're only checking the prefix.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c8b539 and 097fac1.

📒 Files selected for processing (1)
  • src/build/vite/dev.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/build/vite/dev.ts (1)
src/runtime/internal/vite/dev-worker.mjs (2)
  • server (175-188)
  • req (141-141)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: tests-rollup (ubuntu-latest)
  • GitHub Check: tests-rollup (windows-latest)
  • GitHub Check: tests-rolldown (windows-latest)
🔇 Additional comments (2)
src/build/vite/dev.ts (2)

246-247: LGTM! Helpful context.

The comment clearly explains the intent and provides a reference to the related Vite PR for future maintainers.


253-260: Middleware architecture is sound—no backward compatibility risks identified.

The implementation uses a two-tier middleware system: a pre-middleware that conditionally routes certain requests to nitroDevMiddleware, with a fallback middleware that catches all remaining requests. This ensures nothing is dropped:

  • Static assets (extensions): Skip pre-middleware → handled by Vite → fallback runs
  • Dynamic routes (no extension, browser/curl): Pre-middleware routes to Nitro
  • Vite internal routes (/__, /@): Skip pre-middleware → handled by Vite → fallback runs

The sec-fetch-dest header detection is a standard practice to distinguish browser navigation requests, and the extension regex correctly identifies file types. The reference to vitejs/vite/pull/20866 confirms alignment with Vite's own approach. All requests proceed through at least one handler—nothing is blocked.

Comment thread src/build/vite/dev.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/build/vite/dev.ts (1)

256-257: Consider documenting the API route limitation.

Since paths starting with /__ or /@ are now excluded from early dev handling, API routes using these prefixes may not work as expected unless a matching file exists in the project root. Adding a brief comment about this limitation would help prevent developer confusion.

For example:

       // Special prefixes (/__vue-router/auto-routes, /@vite-plugin-layouts/, etc)
+      // Note: API routes with these prefixes require a matching file in project root
       !/^\/(?:__|@).*/.test(req.url!)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 097fac1 and 921e72e.

📒 Files selected for processing (1)
  • src/build/vite/dev.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/build/vite/dev.ts (1)
src/runtime/internal/vite/dev-worker.mjs (2)
  • server (175-188)
  • req (141-141)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: tests-rolldown (windows-latest)
  • GitHub Check: tests-rollup (windows-latest)
  • GitHub Check: tests-rollup (ubuntu-latest)
🔇 Additional comments (1)
src/build/vite/dev.ts (1)

246-263: LGTM! Previous caching concern is now resolved.

The unconditional Vary: sec-fetch-dest header on line 250 correctly addresses the previous review comment about cache correctness. The extended condition logic properly guards against conflicts with Vite's virtual module prefixes (/__, /@) while maintaining support for legitimate SSR/API requests.

Comment thread src/build/vite/dev.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/build/vite/dev.ts (1)

253-254: Fix the comment example (duplicate issue).

The example /src/index.ts has a .ts extension, which contradicts the "No file extension" description. This was flagged in a previous review but hasn't been addressed yet.

Apply this diff:

-      // No file extension (not /src/index.ts)
+      // No file extension (e.g., /api/users)
       !req.url!.match(/\.([a-z0-9]+)(?:[?#]|$)/i)?.[1] &&
🧹 Nitpick comments (1)
src/build/vite/dev.ts (1)

255-256: Consider adding a warning about API route limitations.

The regex correctly excludes paths starting with /__ or /@ to avoid conflicts with Vite plugins. However, the PR description mentions that API routes with these prefixes require special handling (a file must exist in the project root). Consider adding a comment warning developers about this limitation.

Apply this diff to add a clarifying comment:

-      // Special prefixes (/__vue-router/auto-routes, /@vite-plugin-layouts/, etc)
+      // Special prefixes (/__vue-router/auto-routes, /@vite-plugin-layouts/, etc)
+      // Note: API routes starting with /__  or /@ require a corresponding file in project root
       !/^\/(?:__|@)/.test(req.url!)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 921e72e and d0016e0.

📒 Files selected for processing (1)
  • src/build/vite/dev.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/build/vite/dev.ts (1)
src/runtime/internal/vite/dev-worker.mjs (2)
  • server (175-188)
  • req (141-141)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: tests-rolldown (windows-latest)
  • GitHub Check: tests-rollup (ubuntu-latest)
  • GitHub Check: tests-rollup (windows-latest)
🔇 Additional comments (3)
src/build/vite/dev.ts (3)

245-246: LGTM! Clear documentation of middleware ordering.

The comment explains why this middleware runs early and provides a reference to the upstream Vite PR. This helps future maintainers understand the design decision.


249-249: Good fix! Vary header now set unconditionally.

This correctly addresses the previous review comment by ensuring caches know the response varies on the sec-fetch-dest header, preventing incorrect cached responses.


251-252: LGTM! Clear fetch destination filtering.

The condition and comment correctly describe the logic for allowing document-like requests while excluding resource requests (scripts, styles, etc.) that Vite should handle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant