diff --git a/src/config/options.ts b/src/config/options.ts index 165b93acb..327ecc813 100644 --- a/src/config/options.ts +++ b/src/config/options.ts @@ -147,7 +147,6 @@ export async function resolveUserConfig( (removeNodeProtocol ? 'strip' : false) outDir = path.resolve(cwd, outDir) - clean = resolveClean(clean, outDir, cwd) const rawEntry = entry const [resolvedEntry, resolvedRoot] = await resolveEntry( @@ -290,12 +289,11 @@ export async function resolveUserConfig( } /// keep-sorted - const config: Omit = { + const config: Omit = { ...userConfig, alias, attw, cjsDefault, - clean, configDeps, copy: publicDir || copy, css, @@ -346,6 +344,9 @@ export async function resolveUserConfig( const resolvedConfigs = formats.map((fmt, idx): ResolvedConfig => { const once = idx === 0 const overrides = objectFormat ? format[fmt] : undefined + const formatOutDir = overrides?.outDir + ? path.resolve(cwd, overrides.outDir) + : outDir return { ...config, // only copy once @@ -354,6 +355,8 @@ export async function resolveUserConfig( onSuccess: once ? config.onSuccess : undefined, format: normalizeFormat(fmt), ...overrides, + outDir: formatOutDir, + clean: resolveClean(overrides?.clean ?? clean, formatOutDir, cwd), } }) diff --git a/src/features/exe.ts b/src/features/exe.ts index 369fd6554..616b2ec2e 100644 --- a/src/features/exe.ts +++ b/src/features/exe.ts @@ -57,7 +57,7 @@ export function validateSea({ entry, logger, nameLabel, -}: Omit): void { +}: Omit): void { if (process.versions.bun || process.versions.deno) { throw new Error( 'The `exe` option is not supported in Bun and Deno environments.', diff --git a/tests/clean.test.ts b/tests/clean.test.ts index 2b25cf6b8..49baa81b8 100644 --- a/tests/clean.test.ts +++ b/tests/clean.test.ts @@ -220,6 +220,43 @@ describe('clean', () => { expect(oldFileExists).toBe(false) }) + test('should clean per-format outDir when using object format', async (context) => { + const files = { + 'index.ts': 'export const hello = "world"', + } + + // Create per-format directories and stale files first + const testDir = getTestDir(context.task) + const esmPath = path.join(testDir, 'esm') + const cjsPath = path.join(testDir, 'cjs') + + await mkdir(esmPath, { recursive: true }) + await mkdir(cjsPath, { recursive: true }) + + await writeFile(path.join(esmPath, 'old-esm.js'), 'old esm') + await writeFile(path.join(cjsPath, 'old-cjs.js'), 'old cjs') + + // Run build with per-format outDir overrides and clean: true + await testBuild({ + context, + files, + options: { + clean: true, + format: { + esm: { outDir: 'esm' }, + cjs: { outDir: 'cjs' }, + }, + }, + snapshot: false, + }) + + // Verify each per-format outDir was cleaned and new output was produced + expect(await fsExists(path.join(esmPath, 'old-esm.js'))).toBe(false) + expect(await fsExists(path.join(cjsPath, 'old-cjs.js'))).toBe(false) + expect(await fsExists(path.join(esmPath, 'index.mjs'))).toBe(true) + expect(await fsExists(path.join(cjsPath, 'index.cjs'))).toBe(true) + }) + test('should clean files with specific extensions', async (context) => { const files = { 'index.ts': 'export const hello = "world"',