From 211d5331973e0d54f720bc8b338e8bb3f03cd8c4 Mon Sep 17 00:00:00 2001 From: santusht06 <115890693+santusht06@users.noreply.github.com> Date: Mon, 24 Aug 2026 13:48:38 +0530 Subject: [PATCH] fix(optimizer): unblock server.close() when deps were discovered before listen (fix #23143) --- .../optimizer/discoverBeforeListen.spec.ts | 32 +++++++++++++++++++ packages/vite/src/node/optimizer/index.ts | 1 + packages/vite/src/node/optimizer/optimizer.ts | 17 +++++++++- .../vite/src/node/plugins/optimizedDeps.ts | 3 ++ 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/__tests__/optimizer/discoverBeforeListen.spec.ts b/packages/vite/src/node/__tests__/optimizer/discoverBeforeListen.spec.ts index 8b817d09076736..ec08dca77bc5ee 100644 --- a/packages/vite/src/node/__tests__/optimizer/discoverBeforeListen.spec.ts +++ b/packages/vite/src/node/__tests__/optimizer/discoverBeforeListen.spec.ts @@ -85,3 +85,35 @@ test('does not crash when a dep is discovered before the server starts listening await ssr.depsOptimizer?.scanProcessing expect(errors).toStrictEqual([]) }) + +// regression test for https://github.com/vitejs/vite/issues/23143 +// When a module importing a bare specifier is transformed without calling `server.listen()`, +// calling `server.close()` should not hang waiting for optimizer processing promises. +test('server.close() resolves promptly when deps were discovered without calling listen()', async () => { + server = await createServer({ + configFile: false, + root: path.join( + import.meta.dirname, + '../fixtures/optimizer-discover-before-listen', + ), + environments: { + client: { + optimizeDeps: { + force: true, + }, + }, + }, + }) + + await server.environments.client.transformRequest('/entry.js') + + const closePromise = server.close() + const timeoutPromise = setTimeout(2000).then(() => { + throw new Error('server.close() timed out') + }) + + await expect( + Promise.race([closePromise, timeoutPromise]), + ).resolves.toBeUndefined() + server = undefined +}) diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index 05846986800ed1..8fcfb70c0f0fdd 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -68,6 +68,7 @@ export interface DepsOptimizer { getOptimizedDepId: (depInfo: OptimizedDepInfo) => string close: () => Promise + isClosed?: () => boolean options: DepOptimizationOptions } diff --git a/packages/vite/src/node/optimizer/optimizer.ts b/packages/vite/src/node/optimizer/optimizer.ts index 3f4c1f19c56a25..c93c0cd142a9bd 100644 --- a/packages/vite/src/node/optimizer/optimizer.ts +++ b/packages/vite/src/node/optimizer/optimizer.ts @@ -66,6 +66,7 @@ export function createDepsOptimizer( getOptimizedDepId: (depInfo: OptimizedDepInfo) => `${depInfo.file}?v=${depInfo.browserHash}`, close, + isClosed: () => closed, options, } @@ -147,6 +148,16 @@ export function createDepsOptimizer( async function close() { closed = true + if (debounceProcessingHandle) { + clearTimeout(debounceProcessingHandle) + debounceProcessingHandle = undefined + } + if (newDepsToLogHandle) { + clearTimeout(newDepsToLogHandle) + newDepsToLogHandle = undefined + } + resolveEnqueuedProcessingPromises() + depOptimizationProcessing.resolve() await Promise.allSettled([ discover?.cancel(), depsOptimizer.scanProcessing, @@ -753,6 +764,7 @@ export function createDepsOptimizer( export function createExplicitDepsOptimizer( environment: DevEnvironment, ): DepsOptimizer { + let closed = false const depsOptimizer = { metadata: initDepsOptimizerMetadata(environment), isOptimizedDepFile: createIsOptimizedDepFile(environment), @@ -770,7 +782,10 @@ export function createExplicitDepsOptimizer( // the optimizer blocks the server start run: () => {}, - close: async () => {}, + close: async () => { + closed = true + }, + isClosed: () => closed, options: environment.config.optimizeDeps, } diff --git a/packages/vite/src/node/plugins/optimizedDeps.ts b/packages/vite/src/node/plugins/optimizedDeps.ts index 972e93fa9a1e6f..063f8392915869 100644 --- a/packages/vite/src/node/plugins/optimizedDeps.ts +++ b/packages/vite/src/node/plugins/optimizedDeps.ts @@ -100,6 +100,9 @@ export function optimizedDepsPlugin(): Plugin { } return code } catch { + if (depsOptimizer?.isClosed?.()) { + return null + } if ( browserHash && !environment.config.optimizeDeps.ignoreOutdatedRequests