Skip to content

Commit fc08bda

Browse files
fix(dev): handle errors in watchChange hook (#22188)
Co-authored-by: sapphi-red <49056869+sapphi-red@users.noreply.github.com>
1 parent 374bb5d commit fc08bda

File tree

2 files changed

+109
-5
lines changed

2 files changed

+109
-5
lines changed

packages/vite/src/node/__tests__/plugins/hooks.spec.ts

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import path from 'node:path'
2-
import { describe, expect, onTestFinished, test } from 'vitest'
2+
import { describe, expect, onTestFinished, test, vi } from 'vitest'
33
import { build } from '../../build'
44
import type { Plugin } from '../../plugin'
55
import { resolveConfig } from '../../config'
66
import { createServer } from '../../server'
77
import { preview } from '../../preview'
88
import { promiseWithResolvers } from '../../../shared/utils'
9+
import { type Logger, createLogger } from '../../logger'
910

1011
const resolveConfigWithPlugin = (
1112
plugin: Plugin,
@@ -33,12 +34,16 @@ const resolveEntryPlugin: Plugin = {
3334
},
3435
}
3536

36-
const createServerWithPlugin = async (plugin: Plugin) => {
37+
const createServerWithPlugin = async (
38+
plugin: Plugin,
39+
customLogger?: Logger,
40+
) => {
3741
const server = await createServer({
3842
configFile: false,
3943
root: import.meta.dirname,
4044
plugins: [plugin, resolveEntryPlugin],
4145
logLevel: 'error',
46+
customLogger,
4247
server: {
4348
middlewareMode: true,
4449
ws: false,
@@ -346,3 +351,98 @@ describe('supports plugin context', () => {
346351
await server.close()
347352
})
348353
})
354+
355+
describe('watcher add/unlink error handling', () => {
356+
test("'add' event logs error when watchChange throws", async () => {
357+
const { promise, resolve } = promiseWithResolvers<void>()
358+
const error = new Error('async watchChange error')
359+
360+
const logError = vi.fn()
361+
const logger = createLogger('error')
362+
logger.error = (...args) => {
363+
logError(...args)
364+
resolve()
365+
}
366+
367+
const server = await createServerWithPlugin(
368+
{
369+
name: 'test',
370+
watchChange() {
371+
return Promise.reject(error)
372+
},
373+
},
374+
logger,
375+
)
376+
377+
server.watcher.emit(
378+
'add',
379+
path.resolve(import.meta.dirname, 'some-file.js'),
380+
)
381+
382+
await promise
383+
expect(logError).toHaveBeenCalled()
384+
expect(logError).toHaveBeenCalledWith(error)
385+
})
386+
387+
test("'change' event logs error when watchChange throws", async () => {
388+
const { promise, resolve } = promiseWithResolvers<void>()
389+
const error = new Error('async watchChange error')
390+
391+
const logError = vi.fn()
392+
const logger = createLogger('error')
393+
logger.error = (...args) => {
394+
logError(...args)
395+
resolve()
396+
}
397+
398+
const server = await createServerWithPlugin(
399+
{
400+
name: 'test',
401+
watchChange() {
402+
return Promise.reject(error)
403+
},
404+
},
405+
logger,
406+
)
407+
408+
server.watcher.emit(
409+
'change',
410+
path.resolve(import.meta.dirname, 'some-file.js'),
411+
)
412+
413+
await promise
414+
expect(logError).toHaveBeenCalled()
415+
expect(logError).toHaveBeenCalledWith(error)
416+
})
417+
418+
test("'unlink' event logs error when watchChange throws", async () => {
419+
const { promise, resolve } = promiseWithResolvers<void>()
420+
const error = new Error('async watchChange error')
421+
422+
const logError = vi.fn()
423+
const logger = createLogger('error')
424+
logger.error = (...args) => {
425+
logError(...args)
426+
resolve()
427+
}
428+
429+
const server = await createServerWithPlugin(
430+
{
431+
name: 'test',
432+
watchChange() {
433+
return Promise.reject(error)
434+
},
435+
},
436+
logger,
437+
)
438+
439+
server.watcher.emit(
440+
'unlink',
441+
path.resolve(import.meta.dirname, 'some-file.js'),
442+
)
443+
444+
await promise
445+
expect(logError).toHaveBeenCalled()
446+
expect(logError).toHaveBeenCalledWith(error)
447+
})
448+
})

packages/vite/src/node/server/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ export async function _createServer(
887887
await onHMRUpdate(isUnlink ? 'delete' : 'create', file)
888888
}
889889

890-
watcher.on('change', async (file) => {
890+
const onFileChange = async (file: string) => {
891891
file = normalizePath(file)
892892
reloadOnTsconfigChange(server, file)
893893

@@ -901,13 +901,17 @@ export async function _createServer(
901901
environment.moduleGraph.onFileChange(file)
902902
}
903903
await onHMRUpdate('update', file)
904+
}
905+
906+
watcher.on('change', (file) => {
907+
onFileChange(file).catch((e) => server.config.logger.error(e))
904908
})
905909

906910
watcher.on('add', (file) => {
907-
onFileAddUnlink(file, false)
911+
onFileAddUnlink(file, false).catch((e) => server.config.logger.error(e))
908912
})
909913
watcher.on('unlink', (file) => {
910-
onFileAddUnlink(file, true)
914+
onFileAddUnlink(file, true).catch((e) => server.config.logger.error(e))
911915
})
912916

913917
if (!middlewareMode && httpServer) {

0 commit comments

Comments
 (0)