Skip to content

Commit b50f16f

Browse files
committed
fix: redirect devtools mount path to trailing slash
1 parent 94db4d7 commit b50f16f

2 files changed

Lines changed: 91 additions & 2 deletions

File tree

packages/core/src/node/__tests__/plugins-server.test.ts

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { DevToolsDockEntry } from '@vitejs/devtools-kit'
22
import { describe, expect, it } from 'vitest'
3-
import { renderDockImportsMap } from '../plugins/server'
3+
import { redirectDevToolsMountPath, renderDockImportsMap } from '../plugins/server'
44

55
describe('renderDockImportsMap', () => {
66
it('uses default importName when omitted', () => {
@@ -55,3 +55,78 @@ describe('renderDockImportsMap', () => {
5555
expect(code).toContain('r["renderPanel"]')
5656
})
5757
})
58+
59+
describe('redirectDevToolsMountPath', () => {
60+
function callRedirect(url: string, originalUrl = url) {
61+
let statusCode: number | undefined
62+
let location: string | undefined
63+
let ended = false
64+
let nextCalled = false
65+
66+
redirectDevToolsMountPath(
67+
{ originalUrl, url } as any,
68+
{
69+
set statusCode(value: number) {
70+
statusCode = value
71+
},
72+
get statusCode() {
73+
return statusCode ?? 200
74+
},
75+
setHeader(name: string, value: string) {
76+
if (name === 'Location') {
77+
location = value
78+
}
79+
},
80+
end() {
81+
ended = true
82+
},
83+
} as any,
84+
() => {
85+
nextCalled = true
86+
},
87+
)
88+
89+
return {
90+
ended,
91+
location,
92+
nextCalled,
93+
statusCode,
94+
}
95+
}
96+
97+
it('redirects the mounted devtools root to the canonical trailing slash URL', () => {
98+
expect(callRedirect('/', '/.devtools')).toEqual({
99+
ended: true,
100+
location: '/.devtools/',
101+
nextCalled: false,
102+
statusCode: 302,
103+
})
104+
})
105+
106+
it('preserves the query string when redirecting the mounted devtools root', () => {
107+
expect(callRedirect('/?foo=bar', '/.devtools?foo=bar')).toEqual({
108+
ended: true,
109+
location: '/.devtools/?foo=bar',
110+
nextCalled: false,
111+
statusCode: 302,
112+
})
113+
})
114+
115+
it('passes through the canonical trailing slash URL', () => {
116+
expect(callRedirect('/', '/.devtools/')).toEqual({
117+
ended: false,
118+
location: undefined,
119+
nextCalled: true,
120+
statusCode: undefined,
121+
})
122+
})
123+
124+
it('passes through devtools subpaths', () => {
125+
expect(callRedirect('/auth', '/.devtools/auth')).toEqual({
126+
ended: false,
127+
location: undefined,
128+
nextCalled: true,
129+
statusCode: undefined,
130+
})
131+
})
132+
})

packages/core/src/node/plugins/server.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import type { ClientScriptEntry, DevToolsDockEntry, DevToolsNodeContext } from '@vitejs/devtools-kit'
2-
import type { Plugin } from 'vite'
2+
import type { Connect, Plugin } from 'vite'
33
import {
44
DEVTOOLS_DOCK_IMPORTS_VIRTUAL_ID,
55
DEVTOOLS_MOUNT_PATH,
6+
DEVTOOLS_MOUNT_PATH_NO_TRAILING_SLASH,
67
} from '@vitejs/devtools-kit/constants'
78
import { createDevToolsContext } from '../context'
89
import { createDevToolsMiddleware } from '../server'
@@ -34,6 +35,18 @@ export function renderDockImportsMap(docks: Iterable<DevToolsDockEntry>): string
3435
].join('\n')
3536
}
3637

38+
export const redirectDevToolsMountPath: Connect.NextHandleFunction = (req, res, next) => {
39+
const originalUrl = req.originalUrl ?? req.url
40+
if (originalUrl === DEVTOOLS_MOUNT_PATH_NO_TRAILING_SLASH || originalUrl?.startsWith(`${DEVTOOLS_MOUNT_PATH_NO_TRAILING_SLASH}?`)) {
41+
res.statusCode = 302
42+
res.setHeader('Location', `${DEVTOOLS_MOUNT_PATH}${originalUrl.slice(DEVTOOLS_MOUNT_PATH_NO_TRAILING_SLASH.length)}`)
43+
res.end()
44+
return
45+
}
46+
47+
next()
48+
}
49+
3750
export function DevToolsServer(): Plugin {
3851
let context: DevToolsNodeContext
3952
return {
@@ -54,6 +67,7 @@ export function DevToolsServer(): Plugin {
5467
},
5568
context,
5669
})
70+
viteDevServer.middlewares.use(DEVTOOLS_MOUNT_PATH_NO_TRAILING_SLASH, redirectDevToolsMountPath)
5771
viteDevServer.middlewares.use(DEVTOOLS_MOUNT_PATH, middleware)
5872
},
5973
resolveId(id) {

0 commit comments

Comments
 (0)