From 04572d6bd1cdbe6af02f963afa281061b257d256 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Fri, 26 Jun 2026 21:22:38 +0900 Subject: [PATCH] fix(optimize-deps): ignore `ERR_CLOSED_SERVER` in scanner --- packages/vite/src/node/__tests__/scan.spec.ts | 29 +++++++++++++++++++ packages/vite/src/node/optimizer/scan.ts | 16 +++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/__tests__/scan.spec.ts b/packages/vite/src/node/__tests__/scan.spec.ts index 79348c1976f6e5..cf5b69a66bb012 100644 --- a/packages/vite/src/node/__tests__/scan.spec.ts +++ b/packages/vite/src/node/__tests__/scan.spec.ts @@ -256,6 +256,35 @@ test('scan resolves build.rolldownOptions.input relative to the root', async (ct }) }) +// regression test for `The server is being restarted or closed. Request is outdated` +// error in the scanner. The dependency scanner runs in the background and +// may still be crawling when the server is closed. The scan fails because resolutions +// reject with `ERR_CLOSED_SERVER`, but this failure must be ignored (the scan result is +// discarded on close anyway) so it doesn't escape as an unhandled rejection. +test('scan ignores the failure when the server is closed mid-scan', async (ctx) => { + const server = await createServer({ + configFile: false, + logLevel: 'silent', + root: path.join(import.meta.dirname, 'fixtures', 'scan-build-input', 'src'), + optimizeDeps: { + entries: ['./entry-client.tsx'], + force: true, + noDiscovery: false, + }, + }) + ctx.onTestFinished(() => server.close()) + + // Simulate the server being torn down while the scanner is still running. + await server.environments.client.pluginContainer.close() + + const { cancel, result } = scanImports( + devToScanEnvironment(server.environments.client), + ) + ctx.onTestFinished(cancel) + + await expect(result).resolves.toEqual({ deps: {}, missing: {} }) +}) + test('scan import.meta.glob package imports patterns', async (ctx) => { const server = await createServer({ configFile: false, diff --git a/packages/vite/src/node/optimizer/scan.ts b/packages/vite/src/node/optimizer/scan.ts index 8bc452d6695acc..64fd30b268d5a6 100644 --- a/packages/vite/src/node/optimizer/scan.ts +++ b/packages/vite/src/node/optimizer/scan.ts @@ -32,7 +32,10 @@ import { virtualModuleRE, } from '../utils' import type { EnvironmentPluginContainer } from '../server/pluginContainer' -import { createEnvironmentPluginContainer } from '../server/pluginContainer' +import { + ERR_CLOSED_SERVER, + createEnvironmentPluginContainer, +} from '../server/pluginContainer' import { BaseEnvironment } from '../baseEnvironment' import type { DevEnvironment } from '../server/environment' import { transformGlobImport } from '../plugins/importMetaGlob' @@ -165,6 +168,17 @@ export function scanImports(environment: ScanEnvironment): { missing, } } catch (e) { + // The scanner runs in the background and may still be crawling when the + // server is closed. In that case resolutions reject with + // `ERR_CLOSED_SERVER` and the scan build fails. + if ( + e.errors?.some( + (error: { pluginCode?: string }) => + error.pluginCode === ERR_CLOSED_SERVER, + ) + ) { + return + } const prependMessage = colors.red(`\ Failed to scan for dependencies from entries: ${entries.join('\n')}