From 73aa08d663609866ec4c25eff1af3a7300eeefd9 Mon Sep 17 00:00:00 2001 From: NgoQuocViet2001 Date: Fri, 14 Aug 2026 01:54:31 +0700 Subject: [PATCH] fix(config): close bundles when generation fails --- .../node/__tests__/configBundleClose.spec.ts | 47 +++++++++++++++++++ packages/vite/src/node/config.ts | 25 ++++++---- 2 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 packages/vite/src/node/__tests__/configBundleClose.spec.ts diff --git a/packages/vite/src/node/__tests__/configBundleClose.spec.ts b/packages/vite/src/node/__tests__/configBundleClose.spec.ts new file mode 100644 index 00000000000000..22721312952210 --- /dev/null +++ b/packages/vite/src/node/__tests__/configBundleClose.spec.ts @@ -0,0 +1,47 @@ +import fs from 'node:fs' +import os from 'node:os' +import path from 'node:path' +import { afterEach, expect, test, vi } from 'vitest' + +const mocks = vi.hoisted(() => ({ + close: vi.fn(), + generate: vi.fn(), +})) + +vi.mock('rolldown', async (importOriginal) => { + const actual = await importOriginal() + return { + ...actual, + rolldown: vi.fn(async () => ({ + close: mocks.close, + generate: mocks.generate, + })), + } +}) + +let root: string | undefined + +afterEach(() => { + vi.clearAllMocks() + if (root) fs.rmSync(root, { recursive: true, force: true }) + root = undefined +}) + +test('closes the config bundle when generation fails', async () => { + vi.resetModules() + const { loadConfigFromFile } = await import('../config') + root = fs.mkdtempSync(path.join(os.tmpdir(), 'vite-config-bundle-close-')) + const configFile = path.join(root, 'vite.config.js') + fs.writeFileSync(configFile, 'export default {}') + mocks.generate.mockRejectedValueOnce(new Error('generate failed')) + + await expect( + loadConfigFromFile( + { command: 'serve', mode: 'development' }, + configFile, + root, + 'silent', + ), + ).rejects.toThrow('generate failed') + expect(mocks.close).toHaveBeenCalledOnce() +}) diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 9fee3e59a93c77..400739dea2f031 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -20,6 +20,7 @@ import { type OutputChunk, type PluginContextMeta, type RolldownOptions, + type RolldownOutput, rolldown, } from 'rolldown' import { isDynamicPattern } from 'tinyglobby' @@ -2649,16 +2650,20 @@ async function bundleConfigFile( }, ], }) - const result = await bundle.generate({ - format: isESM ? 'esm' : 'cjs', - sourcemap: 'inline', - sourcemapPathTransform(relative) { - return path.resolve(fileName, relative) - }, - // we want to generate a single chunk like esbuild does with `splitting: false` - codeSplitting: false, - }) - await bundle.close() + let result: RolldownOutput + try { + result = await bundle.generate({ + format: isESM ? 'esm' : 'cjs', + sourcemap: 'inline', + sourcemapPathTransform(relative) { + return path.resolve(fileName, relative) + }, + // we want to generate a single chunk like esbuild does with `splitting: false` + codeSplitting: false, + }) + } finally { + await bundle.close() + } const entryChunk = result.output.find( (chunk): chunk is OutputChunk => chunk.type === 'chunk' && chunk.isEntry,