diff --git a/docs/config/server-options.md b/docs/config/server-options.md index 9d1adefba7765e..cd9b809b6b7bd1 100644 --- a/docs/config/server-options.md +++ b/docs/config/server-options.md @@ -176,7 +176,7 @@ The error that appears in the Browser when the fallback happens can be ignored. ## server.watch -- **Type:** `object` +- **Type:** `object | null` File system watcher options to pass on to [chokidar](https://github.com/paulmillr/chokidar#api). @@ -197,6 +197,8 @@ export default defineConfig({ }) ``` +If set to `null`, no files will be watched. `server.watcher` will provide a compatible event emitter, but calling `add` or `unwatch` will have no effect. + ::: warning Using Vite on Windows Subsystem for Linux (WSL) 2 When running Vite on WSL2, file system watching does not work when a file is edited by Windows applications (non-WSL2 process). This is due to [a WSL2 limitation](https://github.com/microsoft/WSL/issues/4739). This also applies to running on Docker with a WSL2 backend. diff --git a/docs/guide/api-javascript.md b/docs/guide/api-javascript.md index c320d5374c70c4..b51f5f4a4bcb51 100644 --- a/docs/guide/api-javascript.md +++ b/docs/guide/api-javascript.md @@ -75,7 +75,8 @@ interface ViteDevServer { */ httpServer: http.Server | null /** - * Chokidar watcher instance. + * Chokidar watcher instance. If `config.server.watch` is set to `null`, + * returns a noop event emitter. * https://github.com/paulmillr/chokidar#api */ watcher: FSWatcher diff --git a/packages/vite/src/node/server/__tests__/watcher.spec.ts b/packages/vite/src/node/server/__tests__/watcher.spec.ts new file mode 100644 index 00000000000000..90b68fcfd88d0f --- /dev/null +++ b/packages/vite/src/node/server/__tests__/watcher.spec.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from 'vitest' +import { createServer } from '../index' + +const stubGetWatchedCode = /getWatched\(\) \{.+?return \{\};.+?\}/s + +describe('watcher configuration', () => { + it('when watcher is disabled, return noop watcher', async () => { + const server = await createServer({ + server: { + watch: null, + }, + }) + expect(server.watcher.getWatched.toString()).toMatch(stubGetWatchedCode) + }) + + it('when watcher is not disabled, return chokidar watcher', async () => { + const server = await createServer({ + server: { + watch: {}, + }, + }) + expect(server.watcher.getWatched.toString()).not.toMatch(stubGetWatchedCode) + }) +}) diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 7510e740a7bfad..d37c37c7bd2cb8 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -45,7 +45,7 @@ import type { BindCLIShortcutsOptions } from '../shortcuts' import { CLIENT_DIR, DEFAULT_DEV_PORT } from '../constants' import type { Logger } from '../logger' import { printServerUrls } from '../logger' -import { resolveChokidarOptions } from '../watch' +import { createNoopWatcher, resolveChokidarOptions } from '../watch' import type { PluginContainer } from './pluginContainer' import { createPluginContainer } from './pluginContainer' import type { WebSocketServer } from './ws' @@ -85,10 +85,10 @@ export interface ServerOptions extends CommonServerOptions { */ hmr?: HmrOptions | boolean /** - * chokidar watch options + * chokidar watch options or null to disable FS watching * https://github.com/paulmillr/chokidar#api */ - watch?: WatchOptions + watch?: WatchOptions | null /** * Create Vite dev server to be used as a middleware in an existing server * @default false @@ -360,11 +360,15 @@ export async function _createServer( setClientErrorHandler(httpServer, config.logger) } - const watcher = chokidar.watch( - // config file dependencies and env file might be outside of root - [root, ...config.configFileDependencies, config.envDir], - resolvedWatchOptions, - ) as FSWatcher + // eslint-disable-next-line eqeqeq + const watchEnabled = serverConfig.watch !== null + const watcher = watchEnabled + ? (chokidar.watch( + // config file dependencies and env file might be outside of root + [root, ...config.configFileDependencies, config.envDir], + resolvedWatchOptions, + ) as FSWatcher) + : createNoopWatcher(resolvedWatchOptions) const moduleGraph: ModuleGraph = new ModuleGraph((url, ssr) => container.resolveId(url, undefined, { ssr }), diff --git a/packages/vite/src/node/watch.ts b/packages/vite/src/node/watch.ts index 64c42a7b97dddc..3b40a71c84d3fc 100644 --- a/packages/vite/src/node/watch.ts +++ b/packages/vite/src/node/watch.ts @@ -1,5 +1,6 @@ +import { EventEmitter } from 'node:events' import glob from 'fast-glob' -import type { WatchOptions } from 'dep-types/chokidar' +import type { FSWatcher, WatchOptions } from 'dep-types/chokidar' import type { ResolvedConfig } from '.' export function resolveChokidarOptions( @@ -23,3 +24,29 @@ export function resolveChokidarOptions( return resolvedWatchOptions } + +class NoopWatcher extends EventEmitter implements FSWatcher { + constructor(public options: WatchOptions) { + super() + } + + add() { + return this + } + + unwatch() { + return this + } + + getWatched() { + return {} + } + + async close() { + // noop + } +} + +export function createNoopWatcher(options: WatchOptions): FSWatcher { + return new NoopWatcher(options) +}