Skip to content

Commit 739847b

Browse files
pyyupsksxzz
andauthored
fix(exports): merge multi-config outputs (#625)
Co-authored-by: Kevin Deng <sxzz@sxzz.moe>
1 parent 4e3a6b9 commit 739847b

File tree

5 files changed

+109
-4
lines changed

5 files changed

+109
-4
lines changed

src/features/exports.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ export interface ExportsOptions {
3636
) => Awaitable<Record<string, any>>
3737
}
3838

39+
export const exportsState: Map<string, Set<TsdownChunks>> = new Map()
40+
3941
export async function writeExports(
4042
options: ResolvedConfig,
4143
chunks: TsdownChunks,
@@ -47,10 +49,19 @@ export async function writeExports(
4749
throw new Error('`package.json` not found, cannot write exports')
4850
}
4951

52+
const stateKey = `${pkg.packageJsonPath as string}::${outDir}`
53+
let chunkSets = exportsState.get(stateKey)
54+
if (!chunkSets) {
55+
chunkSets = new Set()
56+
exportsState.set(stateKey, chunkSets)
57+
}
58+
chunkSets.add(chunks)
59+
const mergedChunks = mergeChunks(chunkSets)
60+
5061
const { publishExports, ...generated } = await generateExports(
5162
pkg,
5263
outDir,
53-
chunks,
64+
mergedChunks,
5465
options.exports,
5566
)
5667

@@ -272,3 +283,18 @@ export function hasExportsTypes(pkg?: PackageJson): boolean {
272283

273284
return false
274285
}
286+
287+
function mergeChunks(chunkSets: Set<TsdownChunks>): TsdownChunks {
288+
const merged: TsdownChunks = {}
289+
for (const chunkSet of chunkSets) {
290+
for (const [format, chunks] of Object.entries(chunkSet) as [
291+
NormalizedFormat,
292+
(OutputChunk | OutputAsset)[],
293+
][]) {
294+
if (!chunks.length) continue
295+
const target = (merged[format] ||= [])
296+
target.push(...chunks)
297+
}
298+
}
299+
return merged
300+
}

src/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ import { attw } from './features/attw.ts'
1919
import { warnLegacyCJS } from './features/cjs.ts'
2020
import { cleanOutDir, cleanupChunks } from './features/clean.ts'
2121
import { copy } from './features/copy.ts'
22-
import { writeExports, type TsdownChunks } from './features/exports.ts'
22+
import {
23+
exportsState,
24+
writeExports,
25+
type TsdownChunks,
26+
} from './features/exports.ts'
2327
import { createHooks, executeOnSuccess } from './features/hooks.ts'
2428
import { publint } from './features/publint.ts'
2529
import {
@@ -45,6 +49,8 @@ export interface TsdownBundle extends AsyncDisposable {
4549
export async function build(
4650
userOptions: InlineConfig = {},
4751
): Promise<TsdownBundle[]> {
52+
exportsState.clear()
53+
4854
globalLogger.level =
4955
userOptions.logLevel || (userOptions.silent ? 'error' : 'info')
5056
const { configs, files: configFiles } = await resolveConfig(userOptions)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## index.node.cjs
2+
3+
```cjs
4+
5+
//#region src/index.node.ts
6+
const platform = "node";
7+
8+
//#endregion
9+
exports.platform = platform;
10+
```

tests/issues.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { readFile } from 'node:fs/promises'
2+
import path from 'node:path'
13
import { exec } from 'tinyexec'
24
import { describe, expect, test } from 'vitest'
35
import { testBuild } from './utils.ts'
@@ -113,4 +115,58 @@ describe('issues', () => {
113115
},
114116
})
115117
})
118+
119+
test('#566', async (context) => {
120+
const { testDir } = await testBuild({
121+
context,
122+
files: {
123+
'src/index.browser.ts': `export const platform = 'browser'`,
124+
'src/index.node.ts': `export const platform = 'node'`,
125+
'tsdown.config.ts': `
126+
export default [
127+
{
128+
entry: './src/index.browser.ts',
129+
format: 'es',
130+
exports: true,
131+
hash: false,
132+
platform: 'browser',
133+
},
134+
{
135+
entry: './src/index.node.ts',
136+
format: 'cjs',
137+
exports: true,
138+
hash: false,
139+
platform: 'node',
140+
},
141+
]
142+
`,
143+
'package.json': JSON.stringify({
144+
name: 'issue-566',
145+
version: '1.0.0',
146+
}),
147+
'tsconfig.json': JSON.stringify({
148+
compilerOptions: { moduleResolution: 'bundler' },
149+
}),
150+
},
151+
options: {
152+
entry: undefined,
153+
config: 'tsdown.config.ts',
154+
dts: false,
155+
},
156+
expectPattern: '**/*.{js,cjs,d.mts}',
157+
})
158+
159+
const pkg = JSON.parse(
160+
await readFile(path.join(testDir, 'package.json'), 'utf8'),
161+
)
162+
expect(pkg.main).toBe('./dist/index.node.cjs')
163+
expect(pkg.module).toBe('./dist/index.browser.mjs')
164+
expect(pkg.exports).toEqual({
165+
'.': {
166+
import: './dist/index.browser.mjs',
167+
require: './dist/index.node.cjs',
168+
},
169+
'./package.json': './package.json',
170+
})
171+
})
116172
})

tests/utils.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'node:url'
55
import { expectFilesSnapshot } from '@sxzz/test-utils'
66
import { glob } from 'tinyglobby'
77
import { mergeUserOptions } from '../src/config/options.ts'
8-
import { build, type UserConfig } from '../src/index.ts'
8+
import { build } from '../src/index.ts'
99
import type { InlineConfig } from '../src/config/index.ts'
1010
import type { RollupLog } from 'rolldown'
1111
import type { RunnerTask, TestContext } from 'vitest'
@@ -92,7 +92,7 @@ export interface TestBuildOptions {
9292
/**
9393
* The options for the build.
9494
*/
95-
options?: UserConfig | ((cwd: string) => UserConfig)
95+
options?: InlineConfig | ((cwd: string) => InlineConfig)
9696

9797
/**
9898
* The working directory of the test. It's a relative path to the test directory.
@@ -162,6 +162,13 @@ export async function testBuild({
162162
return options
163163
},
164164
}
165+
if (
166+
userOptions &&
167+
userOptions.entry == null &&
168+
Object.hasOwn(userOptions, 'entry')
169+
) {
170+
delete resolvedOptions.entry
171+
}
165172
await beforeBuild?.()
166173
await build(resolvedOptions)
167174
restoreCwd()

0 commit comments

Comments
 (0)