Skip to content

fix(vite): keep ?import module requests on vite in dev#4453

Open
n0liu wants to merge 1 commit into
nitrojs:mainfrom
n0liu:fix/vite-dev-import-query
Open

fix(vite): keep ?import module requests on vite in dev#4453
n0liu wants to merge 1 commit into
nitrojs:mainfrom
n0liu:fix/vite-dev-import-query

Conversation

@n0liu

@n0liu n0liu commented Jul 21, 2026

Copy link
Copy Markdown

Fixes #4433

In dev, a module graph fetch for an imported .json (/x.json?import) was answered by the SSR catch-all with HTML instead of the transformed module whenever Sec-Fetch-Dest was absent (plain-HTTP non-loopback origins): json is not in ASSET_EXT_RE, so the extension fallback classified the request as a navigation.

Rather than widening ASSET_EXT_RE, this keys off the ?import query Vite puts on module graph fetches. That marker only ever comes from the module graph — a page navigation never carries it — so it stays authoritative for the extensions the regex deliberately leaves out, without diverting public/*.json or catch-all JSON routes to Vite the way widening the regex would.

  • src/build/vite/dev.ts — treat ?import as an asset signal in the fallback branch, the one reached when Sec-Fetch-Dest is absent or empty.
  • test/vite/app.test.ts — regression test next to the existing Accessing via a non-localhost URL breaks vite dev server #4234 cases. It fails on main (the SSR catch-all answers 200) and passes with the fix.

Verified locally: vitest run test/vite/ (40 passed, no regressions in the #4234/#4241/#4252/#4270 routing cases), pnpm lint and pnpm typecheck clean.

An imported `.json` has no extension in `ASSET_EXT_RE`, so with `Sec-Fetch-Dest`
absent the dev middleware handed `/x.json?import` to the SSR catch-all, which
answered it with HTML. Vite only ever tags module graph fetches with `?import`,
so treat that query as an authoritative asset signal in the fallback branch.
@n0liu
n0liu requested a review from pi0 as a code owner July 21, 2026 02:18
@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

@n0liu is attempting to deploy a commit to the Nitro Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The Vite dev middleware now recognizes ?import and &import module-graph requests as assets, including requests without Sec-Fetch-Dest. A Vite integration test verifies these requests are not handled by Nitro’s SSR catch-all.

Changes

Vite import routing

Layer / File(s) Summary
Import-query asset classification
src/build/vite/dev.ts, test/vite/app.test.ts
Adds VITE_IMPORT_QUERY_RE and uses it to classify import-query requests as assets when Sec-Fetch-Dest is "empty". The test verifies an imported missing JSON module is not returned as SSR HTML.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • nitrojs/nitro#4238: Related Vite dev request classification when Sec-Fetch-Dest is absent.
  • nitrojs/nitro#4272: Related asset-versus-navigation routing heuristics in the Vite dev middleware.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title follows conventional commit format and accurately summarizes the Vite dev import-query fix.
Description check ✅ Passed The description is directly related to the changeset and explains the dev middleware fix and regression test.
Linked Issues check ✅ Passed The changes address #4433 by treating ?import module requests as assets and adding a regression test.
Out of Scope Changes check ✅ Passed No unrelated code changes are evident beyond the requested Vite routing fix and test coverage.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/build/vite/dev.ts`:
- Around line 27-30: Update the Vite import detection using VITE_IMPORT_QUERY_RE
so it evaluates only the URL query portion, such as parsed url.search or
URLSearchParams, rather than the full URL pathname. Preserve detection of the
import parameter while ensuring paths like /page&import are not classified as
module requests, and add a regression case covering that pathname.

In `@test/vite/app.test.ts`:
- Around line 85-96: Strengthen the assertions in the test “does not let the SSR
catch-all swallow ?import module requests” to verify Vite handled the request:
assert the expected missing-module HTTP status and that the response is
non-HTML, or use an existing fixture and assert its transformed JavaScript
response instead of only checking status is not 200.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9d2c934d-2423-4d73-ac8e-97de0a0780a3

📥 Commits

Reviewing files that changed from the base of the PR and between bfc2f5e and 9d17ea7.

📒 Files selected for processing (2)
  • src/build/vite/dev.ts
  • test/vite/app.test.ts

Comment thread src/build/vite/dev.ts
Comment on lines +27 to +30
// Vite tags module graph fetches for files it has to serve as modules (e.g. an imported `.json`)
// with an `?import` query. Only the module graph emits it — a page navigation never does — so it
// stays authoritative for extensions deliberately left out of `ASSET_EXT_RE` (#4433).
const VITE_IMPORT_QUERY_RE = /[?&]import(?:[&=]|$)/;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restrict ?import detection to the query string.

The regex is applied to the entire URL, so a valid pathname such as /page&import can be misclassified as a Vite module request when Sec-Fetch-Dest is absent or empty. Parse url.search/URLSearchParams first, then check for the import parameter; add a regression case for this pathname.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/build/vite/dev.ts` around lines 27 - 30, Update the Vite import detection
using VITE_IMPORT_QUERY_RE so it evaluates only the URL query portion, such as
parsed url.search or URLSearchParams, rather than the full URL pathname.
Preserve detection of the import parameter while ensuring paths like
/page&import are not classified as module requests, and add a regression case
covering that pathname.

Comment thread test/vite/app.test.ts
Comment on lines +85 to +96
// #4433: Vite marks module-graph fetches for files it has to serve as modules with an `?import`
// query. The marker only ever comes from the module graph, never from a page navigation, so such
// a request must reach Vite even when the extension is not a known asset type (`.json`) and
// `Sec-Fetch-Dest` is absent.
test("does not let the SSR catch-all swallow ?import module requests", async () => {
const res = await fetch(`${serverURL}/missing-module.json?import`, {
headers: { accept: "*/*" },
redirect: "manual",
});
expect(res.status).not.toBe(200);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the Vite response more specifically.

not.toBe(200) can pass for unrelated failures such as a 500 or redirect, so this does not prove the request bypassed Nitro’s SSR catch-all. Assert the expected missing-module status and non-HTML response, or use an existing fixture and verify Vite’s transformed JavaScript response.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/vite/app.test.ts` around lines 85 - 96, Strengthen the assertions in the
test “does not let the SSR catch-all swallow ?import module requests” to verify
Vite handled the request: assert the expected missing-module HTTP status and
that the response is non-HTML, or use an existing fixture and assert its
transformed JavaScript response instead of only checking status is not 200.

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.

Dev middleware returns HTML for imported .json modules when Sec-Fetch-Dest is missing (json not in ASSET_EXT_RE)

1 participant