Skip to content

Commit 6bc6c4d

Browse files
authored
fix(dev): skip JS responses for document requests (#20866)
1 parent c1caacd commit 6bc6c4d

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

packages/vite/src/node/server/middlewares/transform.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ const debugCache = createDebugger('vite:cache')
4040

4141
const knownIgnoreList = new Set(['/', '/favicon.ico'])
4242

43+
const documentFetchDests = new Set([
44+
'document',
45+
'iframe',
46+
'frame',
47+
'fencedframe',
48+
])
49+
function isDocumentFetchDest(req: Connect.IncomingMessage) {
50+
const fetchDest = req.headers['sec-fetch-dest']
51+
return fetchDest !== undefined && documentFetchDests.has(fetchDest)
52+
}
53+
4354
// TODO: consolidate this regex pattern with the url, raw, and inline checks in plugins
4455
const urlRE = /[?&]url\b/
4556
const rawRE = /[?&]raw\b/
@@ -63,6 +74,11 @@ export function cachedTransformMiddleware(
6374
return function viteCachedTransformMiddleware(req, res, next) {
6475
const environment = server.environments.client
6576

77+
if (isDocumentFetchDest(req)) {
78+
res.appendHeader('Vary', 'Sec-Fetch-Dest')
79+
return next()
80+
}
81+
6682
// check if we can return 304 early
6783
const ifNoneMatch = req.headers['if-none-match']
6884
if (ifNoneMatch) {
@@ -102,7 +118,8 @@ export function transformMiddleware(
102118

103119
if (
104120
(req.method !== 'GET' && req.method !== 'HEAD') ||
105-
knownIgnoreList.has(req.url!)
121+
knownIgnoreList.has(req.url!) ||
122+
isDocumentFetchDest(req)
106123
) {
107124
return next()
108125
}

playground/html/__tests__/html.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,16 @@ describe('link with props', () => {
273273
})
274274
})
275275

276+
describe.runIf(isServe)('SPA fallback', () => {
277+
test('should serve index.html via page navigation even when path matches file basename', async () => {
278+
const response = await page.goto(viteTestUrl + '/test')
279+
expect(response.status()).toBe(200)
280+
const content = await page.content()
281+
expect(content).toContain('Transformed')
282+
expect(content).not.toContain('This is test.js')
283+
})
284+
})
285+
276286
describe.runIf(isServe)('invalid', () => {
277287
test('should be 500 with overlay', async () => {
278288
const response = await page.goto(viteTestUrl + '/invalid.html')

playground/html/test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// This file is used to test https://github.com/vitejs/vite/issues/20705
2+
// The dev server should NOT serve this file when navigating to /test
3+
export const message =
4+
'This is test.js - should not be served for /test navigation'

0 commit comments

Comments
 (0)