Skip to content

Commit 2fa4bba

Browse files
authored
fix(core): close ws transport on vite server shutdown (#519)
1 parent 627968f commit 2fa4bba

2 files changed

Lines changed: 53 additions & 2 deletions

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import type { ViteDevServer } from 'vite'
2+
import { beforeEach, describe, expect, it, vi } from 'vitest'
3+
import { createDevToolsContext } from '../context'
4+
import { DevToolsServer } from '../plugins/server'
5+
import { createDevToolsHub } from '../server'
6+
7+
vi.mock('../context', () => ({
8+
createDevToolsContext: vi.fn(),
9+
}))
10+
11+
vi.mock('../server', () => ({
12+
createDevToolsHub: vi.fn(),
13+
}))
14+
15+
describe('devToolsServer lifecycle', () => {
16+
beforeEach(() => {
17+
vi.clearAllMocks()
18+
})
19+
20+
it('closes the DevTools middleware with the Vite server', async () => {
21+
const close = vi.fn(async () => {})
22+
const middleware = vi.fn()
23+
vi.mocked(createDevToolsContext).mockResolvedValue({} as Awaited<ReturnType<typeof createDevToolsContext>>)
24+
vi.mocked(createDevToolsHub).mockResolvedValue({ close, middleware } as unknown as Awaited<ReturnType<typeof createDevToolsHub>>)
25+
26+
const viteDevServer = {
27+
config: {
28+
root: process.cwd(),
29+
server: {},
30+
},
31+
middlewares: {
32+
use: vi.fn(),
33+
},
34+
} as unknown as ViteDevServer
35+
const plugin = DevToolsServer()
36+
37+
const { closeBundle, configureServer } = plugin
38+
if (typeof configureServer !== 'function' || typeof closeBundle !== 'function')
39+
throw new TypeError('Expected DevTools server lifecycle hooks')
40+
41+
await configureServer.call({} as never, viteDevServer)
42+
await closeBundle.call({} as never)
43+
44+
expect(close).toHaveBeenCalledOnce()
45+
})
46+
})

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export function renderDockImportsMap(docks: Iterable<DevToolsDockEntry>): string
3838

3939
export function DevToolsServer(): Plugin {
4040
let context: ViteDevToolsNodeContext
41+
let close: (() => Promise<void>) | undefined
4142
return {
4243
name: 'vite:devtools:server',
4344
enforce: 'post',
@@ -49,7 +50,7 @@ export function DevToolsServer(): Plugin {
4950
? '0.0.0.0'
5051
: viteDevServer.config.server.host || 'localhost'
5152

52-
const { middleware } = await createDevToolsHub({
53+
const devtools = await createDevToolsHub({
5354
context,
5455
// Share Vite's HTTP server for a route-bound WS upgrade; fall back to a
5556
// side-car when Vite runs in middleware mode without its own server.
@@ -58,6 +59,7 @@ export function DevToolsServer(): Plugin {
5859
server: (viteDevServer.httpServer ?? undefined) as NodeHttpServer | undefined,
5960
host,
6061
})
62+
close = devtools.close
6163
viteDevServer.middlewares.use((req, res, next) => {
6264
if (req.url === DEVTOOLS_MOUNT_PATH_NO_TRAILING_SLASH || req.url?.startsWith(`${DEVTOOLS_MOUNT_PATH_NO_TRAILING_SLASH}?`)) {
6365
res.statusCode = 302
@@ -70,7 +72,10 @@ export function DevToolsServer(): Plugin {
7072
})
7173
// The hub middleware answers the whole `/__devtools/` surface and
7274
// `next()`s outside its base, so mount it at the server root.
73-
viteDevServer.middlewares.use(middleware)
75+
viteDevServer.middlewares.use(devtools.middleware)
76+
},
77+
async closeBundle() {
78+
await close?.()
7479
},
7580
resolveId(id) {
7681
if (id === DEVTOOLS_DOCK_IMPORTS_VIRTUAL_ID) {

0 commit comments

Comments
 (0)