From c5068eb251b88d38cbf4dd5cb5b8fdf0ee53a7ee Mon Sep 17 00:00:00 2001 From: Kevin Deng Date: Fri, 15 May 2026 22:15:25 +0900 Subject: [PATCH 1/3] Document outExtension migration and IIFE filename differences --- docs/guide/migrate-from-tsup.md | 22 +++++++-- docs/options/output-format.md | 3 ++ docs/zh-CN/guide/migrate-from-tsup.md | 22 +++++++-- docs/zh-CN/options/output-format.md | 3 ++ .../__snapshots__/tsup-config.test.ts.snap | 22 +++++++++ .../migrate/src/helpers/tsup-config.test.ts | 28 +++++++++++ packages/migrate/src/helpers/tsup-config.ts | 33 ++++++++----- skills/tsdown-migrate/SKILL.md | 7 ++- .../references/guide-differences-detailed.md | 5 ++ .../references/guide-option-mappings.md | 4 ++ .../references/guide-migrate-from-tsup.md | 10 ++++ .../references/option-output-directory.md | 4 +- .../tsdown/references/option-output-format.md | 6 ++- src/config/options.ts | 20 +++++++- src/config/types.ts | 6 +++ .../deprecated-custom-extension.snap.md | 9 ++++ tests/e2e.test.ts | 47 +++++++++++++++++++ 17 files changed, 227 insertions(+), 24 deletions(-) create mode 100644 tests/__snapshots__/deprecated-custom-extension.snap.md diff --git a/docs/guide/migrate-from-tsup.md b/docs/guide/migrate-from-tsup.md index 8090bd1d4..f3512627b 100644 --- a/docs/guide/migrate-from-tsup.md +++ b/docs/guide/migrate-from-tsup.md @@ -54,10 +54,11 @@ While `tsdown` aims to be highly compatible with `tsup`, there are some differen Some options have been renamed for clarity: -| tsup | tsdown | Notes | -| ---------------- | ------------ | ---------------------------------- | -| `cjsInterop` | `cjsDefault` | CJS default export handling | -| `esbuildPlugins` | `plugins` | Now uses Rolldown/Unplugin plugins | +| tsup | tsdown | Notes | +| ---------------- | --------------- | ---------------------------------- | +| `cjsInterop` | `cjsDefault` | CJS default export handling | +| `esbuildPlugins` | `plugins` | Now uses Rolldown/Unplugin plugins | +| `outExtension` | `outExtensions` | Custom output extensions | ### Deprecated but Compatible Options @@ -76,6 +77,19 @@ The following tsup options still work in tsdown for backward compatibility, but tsdown also adds `deps.onlyBundle` for whitelisting allowed bundled packages. +### Output Filename Differences + +For IIFE builds, `tsdown` emits names like `[name].iife.js`, while `tsup` commonly emitted `[name].global.js`. `outExtensions` customizes output extensions or suffixes, but it does not remove the built-in `.iife` or `.umd` segment. To preserve older full filename patterns, use Rolldown output options: + +```ts +export default { + format: 'iife', + outputOptions: { + entryFileNames: '[name].global.js', + }, +} +``` + ### Plugin System tsdown uses [Rolldown](https://rolldown.rs/) plugins instead of esbuild plugins. If you use [unplugin](https://github.com/unjs/unplugin) plugins, update the import path: diff --git a/docs/options/output-format.md b/docs/options/output-format.md index 51d38cfa9..30ec16117 100644 --- a/docs/options/output-format.md +++ b/docs/options/output-format.md @@ -32,6 +32,9 @@ tsdown --format iife > [!NOTE] > **CJS is in maintenance-only mode.** Since the ecosystem is transitioning to ESM and Node.js now supports `require(esm)`, `tsdown`'s CJS-specific features (such as [`cjsDefault`](./cjs-default.md)) are kept for compatibility but will not be further enhanced or optimized. New libraries are encouraged to publish ESM-only. +> [!NOTE] +> IIFE and UMD outputs include the format in their filenames by default, such as `index.iife.js` and `index.umd.js`. If you need a custom full filename pattern, such as the `tsup`-style `index.global.js`, set `outputOptions.entryFileNames`. + ## Overriding Configuration by Format You can override specific configuration options for each output format by setting `format` as an object in your config file. This allows you to tailor settings such as `target` or other options for each format individually. diff --git a/docs/zh-CN/guide/migrate-from-tsup.md b/docs/zh-CN/guide/migrate-from-tsup.md index c28408360..409458a15 100644 --- a/docs/zh-CN/guide/migrate-from-tsup.md +++ b/docs/zh-CN/guide/migrate-from-tsup.md @@ -54,10 +54,11 @@ npx tsdown-migrate packages/foo packages/bar 部分选项已重命名以提高清晰度: -| tsup | tsdown | 说明 | -| ---------------- | ------------ | ----------------------------- | -| `cjsInterop` | `cjsDefault` | CJS 默认导出处理 | -| `esbuildPlugins` | `plugins` | 现使用 Rolldown/Unplugin 插件 | +| tsup | tsdown | 说明 | +| ---------------- | --------------- | ----------------------------- | +| `cjsInterop` | `cjsDefault` | CJS 默认导出处理 | +| `esbuildPlugins` | `plugins` | 现使用 Rolldown/Unplugin 插件 | +| `outExtension` | `outExtensions` | 自定义输出扩展名 | ### 已弃用但兼容的选项 @@ -76,6 +77,19 @@ npx tsdown-migrate packages/foo packages/bar tsdown 还新增了 `deps.onlyBundle`,用于白名单指定允许打包的依赖。 +### 输出文件名差异 + +对于 IIFE 构建,`tsdown` 会输出类似 `[name].iife.js` 的文件名,而 `tsup` 常见输出是 `[name].global.js`。`outExtensions` 用于自定义输出扩展名或后缀,但不会移除内置的 `.iife` 或 `.umd` 片段。如果需要保留旧的完整文件名模式,请使用 Rolldown 的输出选项: + +```ts +export default { + format: 'iife', + outputOptions: { + entryFileNames: '[name].global.js', + }, +} +``` + ### 插件系统 tsdown 使用 [Rolldown](https://rolldown.rs/) 插件代替 esbuild 插件。如果您使用 [unplugin](https://github.com/unjs/unplugin) 插件,需更新导入路径: diff --git a/docs/zh-CN/options/output-format.md b/docs/zh-CN/options/output-format.md index 7a9a2fea2..47ff5c035 100644 --- a/docs/zh-CN/options/output-format.md +++ b/docs/zh-CN/options/output-format.md @@ -32,6 +32,9 @@ tsdown --format iife > [!NOTE] > **CJS 处于仅维护模式。** 由于生态系统正在向 ESM 迁移,且 Node.js 已支持 `require(esm)`,`tsdown` 中 CJS 专属的功能(例如 [`cjsDefault`](./cjs-default.md))仅保留以确保兼容性,不会再进一步增强或优化。建议新库直接发布为 ESM-only。 +> [!NOTE] +> IIFE 和 UMD 输出默认会在文件名中包含格式片段,例如 `index.iife.js` 和 `index.umd.js`。如果需要自定义完整文件名模式,例如 `tsup` 风格的 `index.global.js`,请设置 `outputOptions.entryFileNames`。 + ## 按格式覆盖配置 您可以在配置文件中将 `format` 设置为对象,从而为每种输出格式单独覆盖特定配置选项。这允许您为每个格式分别定制如 `target` 等设置。 diff --git a/packages/migrate/src/helpers/__snapshots__/tsup-config.test.ts.snap b/packages/migrate/src/helpers/__snapshots__/tsup-config.test.ts.snap index d125f33dc..95b184c88 100644 --- a/packages/migrate/src/helpers/__snapshots__/tsup-config.test.ts.snap +++ b/packages/migrate/src/helpers/__snapshots__/tsup-config.test.ts.snap @@ -141,6 +141,28 @@ exports[`option transformations > entryPoints should transform to entry > code 1 }" `; +exports[`option transformations > outExtension method should transform to outExtensions > code 1`] = ` +"export default { + format: 'esm', + outExtensions() { + return { js: '.mjs' } + }, + clean: false, + dts: false, + target: false, +}" +`; + +exports[`option transformations > outExtension property should transform to outExtensions > code 1`] = ` +"export default { + format: 'esm', + outExtensions: () => ({ js: '.mjs' }), + clean: false, + dts: false, + target: false, +}" +`; + exports[`option transformations > publicDir should transform to copy > code 1`] = ` "export default { copy: 'public', diff --git a/packages/migrate/src/helpers/tsup-config.test.ts b/packages/migrate/src/helpers/tsup-config.test.ts index 2f380d131..3dfcdbbc7 100644 --- a/packages/migrate/src/helpers/tsup-config.test.ts +++ b/packages/migrate/src/helpers/tsup-config.test.ts @@ -107,6 +107,34 @@ describe('option transformations', () => { expect(code).not.toContain('publicDir') }) + test('outExtension property should transform to outExtensions', () => { + const input = ` + export default { + format: 'esm', + outExtension: () => ({ js: '.mjs' }), + } + ` + const { code } = transform(input, 'tsup.config.ts') + expect(code).toContain('outExtensions:') + expect(code).toContain("js: '.mjs'") + expect(code).not.toContain('outExtension:') + }) + + test('outExtension method should transform to outExtensions', () => { + const input = ` + export default { + format: 'esm', + outExtension() { + return { js: '.mjs' } + }, + } + ` + const { code } = transform(input, 'tsup.config.ts') + expect(code).toContain('outExtensions()') + expect(code).toContain("js: '.mjs'") + expect(code).not.toContain('outExtension()') + }) + test('removeNodeProtocol should transform to nodeProtocol: "strip"', () => { const input = ` export default { diff --git a/packages/migrate/src/helpers/tsup-config.ts b/packages/migrate/src/helpers/tsup-config.ts index 422635b39..d98e60b66 100644 --- a/packages/migrate/src/helpers/tsup-config.ts +++ b/packages/migrate/src/helpers/tsup-config.ts @@ -30,6 +30,7 @@ const WARNING_MESSAGES: Record = { const PROPERTY_RENAMES: Record = { entryPoints: 'entry', esbuildPlugins: 'plugins', + outExtension: 'outExtensions', publicDir: 'copy', cjsInterop: 'cjsDefault', } @@ -101,24 +102,34 @@ export function transformTsupConfig( edits.push(node.replace(text.replace('/esbuild', '/rolldown'))) } - // Helper: Find property identifier (key only) by name using relational rule - const findPropertyIdentifier = (propName: string): SgNode | null => { - return root.find({ + // Helper: Find property identifiers (keys only) by name using relational rules + const findPropertyIdentifiers = (propName: string): SgNode[] => { + return root.findAll({ rule: { - kind: 'property_identifier', - regex: `^${propName}$`, - inside: { - kind: 'pair', - field: 'key', - }, + any: [ + { + kind: 'property_identifier', + regex: `^${propName}$`, + inside: { + kind: 'pair', + field: 'key', + }, + }, + { + kind: 'property_identifier', + regex: `^${propName}$`, + inside: { + kind: 'method_definition', + }, + }, + ], }, }) } // 3. Rename properties using AST - only replace the key identifier for (const [oldName, newName] of Object.entries(PROPERTY_RENAMES)) { - const propIdentifier = findPropertyIdentifier(oldName) - if (propIdentifier) { + for (const propIdentifier of findPropertyIdentifiers(oldName)) { edits.push(propIdentifier.replace(newName)) } } diff --git a/skills/tsdown-migrate/SKILL.md b/skills/tsdown-migrate/SKILL.md index 97d6c926c..b6c830514 100644 --- a/skills/tsdown-migrate/SKILL.md +++ b/skills/tsdown-migrate/SKILL.md @@ -69,6 +69,7 @@ Replace all identifiers: `tsup` → `tsdown`, `TSUP` → `TSDOWN`. |------|--------|-------| | `cjsInterop` | `cjsDefault` | CJS default export handling | | `esbuildPlugins` | `plugins` | Now uses Rolldown/Unplugin plugins | +| `outExtension` | `outExtensions` | Custom output extensions | ### Deprecated but Compatible @@ -87,6 +88,10 @@ These tsup options still work in tsdown for backward compatibility, but emit dep | `noExternal: [...]` | `deps: { alwaysBundle: [...] }` | Moved to deps namespace | | `skipNodeModulesBundle` | `deps: { skipNodeModulesBundle: true }` | Moved to deps namespace | +### Output Filename Differences + +For IIFE builds, `tsdown` emits names like `[name].iife.js`, while `tsup` commonly emitted `[name].global.js`. `outExtensions` customizes extensions or suffixes, but it does not remove the built-in `.iife` or `.umd` segment. Use `outputOptions.entryFileNames: '[name].global.js'` to preserve old IIFE filenames. + ### Dependency Namespace Moves Dependencies config moved under `deps` namespace. If both `external` and `noExternal` exist, merge into a single `deps` object: @@ -235,7 +240,7 @@ Use this checklist when performing a migration: - [ ] Rename tsup.config.* → tsdown.config.* - [ ] Update import from 'tsup' to 'tsdown' - [ ] Replace tsup/TSUP identifiers with tsdown/TSDOWN -- [ ] Apply property renames (cjsInterop→cjsDefault, esbuildPlugins→plugins) +- [ ] Apply property renames (cjsInterop→cjsDefault, esbuildPlugins→plugins, outExtension→outExtensions) - [ ] Migrate deprecated options (publicDir→copy, bundle→unbundle, removeNodeProtocol→nodeProtocol, injectStyle→css.inject) - [ ] Move external/noExternal/skipNodeModulesBundle into deps namespace - [ ] Update unplugin imports from /esbuild to /rolldown diff --git a/skills/tsdown-migrate/references/guide-differences-detailed.md b/skills/tsdown-migrate/references/guide-differences-detailed.md index fc817bf27..70ca64261 100644 --- a/skills/tsdown-migrate/references/guide-differences-detailed.md +++ b/skills/tsdown-migrate/references/guide-differences-detailed.md @@ -45,6 +45,7 @@ Comprehensive comparison of tsdown and tsup for understanding migration impact a |---------|------|--------|--------| | CJS interop | `cjsInterop` | `cjsDefault` | Property rename | | Plugins | `esbuildPlugins` | `plugins` | Different plugin format (Rolldown) | +| Output extensions | `outExtension` | `outExtensions` | Property rename | ### Deprecated but Compatible @@ -61,6 +62,10 @@ These tsup options still work in tsdown but emit deprecation warnings. They will | Inline deps | `noExternal` | `deps.alwaysBundle` | Moved to deps namespace | | Skip node_modules | `skipNodeModulesBundle` | `deps.skipNodeModulesBundle` | Moved to deps namespace | +### Output Filename Differences + +For IIFE builds, `tsdown` emits `[name].iife.js`; `tsup` commonly emitted `[name].global.js`. `outExtensions` customizes extensions or suffixes, but it does not remove `.iife` or `.umd`. Use `outputOptions.entryFileNames` for full filename patterns such as `[name].global.js`. + ### Not Supported | Feature | Reason | Alternative | diff --git a/skills/tsdown-migrate/references/guide-option-mappings.md b/skills/tsdown-migrate/references/guide-option-mappings.md index c65fbc889..6acf5a0fa 100644 --- a/skills/tsdown-migrate/references/guide-option-mappings.md +++ b/skills/tsdown-migrate/references/guide-option-mappings.md @@ -38,6 +38,10 @@ export default defineConfig({ Note: All `unplugin-*/esbuild` imports must change to `unplugin-*/rolldown`. +### outExtension → outExtensions + +`outExtension` was renamed to `outExtensions`. + ## Deprecated but Compatible These options still work in tsdown for backward compatibility but emit deprecation warnings. Migrate them immediately — they will be removed in a future version. diff --git a/skills/tsdown/references/guide-migrate-from-tsup.md b/skills/tsdown/references/guide-migrate-from-tsup.md index e06451c3f..b0568e50d 100644 --- a/skills/tsdown/references/guide-migrate-from-tsup.md +++ b/skills/tsdown/references/guide-migrate-from-tsup.md @@ -42,6 +42,16 @@ npx tsdown-migrate packages/foo packages/bar | `dts` | `false` | Auto-enabled if `types`/`typings` in package.json | | `target` | Manual | Auto-read from `engines.node` in package.json | +### Option Renames + +| tsup | tsdown | +|------|--------| +| `outExtension` | `outExtensions` | + +### Output Filename Differences + +For IIFE builds, `tsdown` emits `[name].iife.js`; `tsup` commonly emitted `[name].global.js`. `outExtensions` customizes extensions or suffixes, but it does not remove `.iife` or `.umd`. Use `outputOptions.entryFileNames: '[name].global.js'` to preserve old IIFE filenames. + ### New Features in tsdown #### Node Protocol Control diff --git a/skills/tsdown/references/option-output-directory.md b/skills/tsdown/references/option-output-directory.md index eda3caf5a..bcc0e9769 100644 --- a/skills/tsdown/references/option-output-directory.md +++ b/skills/tsdown/references/option-output-directory.md @@ -122,9 +122,11 @@ export default defineConfig({ |--------|-------------------|----------------------| | `esm` | `.mjs` | `.js` | | `cjs` | `.cjs` | `.js` | -| `iife` | `.global.js` | `.global.js` | +| `iife` | `.iife.js` | `.iife.js` | | `umd` | `.umd.js` | `.umd.js` | +For IIFE/UMD builds, `outExtensions` customizes extensions or suffixes but does not remove the built-in `.iife` or `.umd` segment. Use `outputOptions.entryFileNames` for custom full filename patterns such as `[name].global.js`. + ### ESM with .js Extension ```ts diff --git a/skills/tsdown/references/option-output-format.md b/skills/tsdown/references/option-output-format.md index e6946ae05..a3538bf86 100644 --- a/skills/tsdown/references/option-output-format.md +++ b/skills/tsdown/references/option-output-format.md @@ -99,7 +99,7 @@ export default defineConfig({ }) ``` -Output: `dist/index.global.js` (IIFE with global `MyLib`) +Output: `dist/index.iife.js` (IIFE with global `MyLib`) ### Universal Library (UMD) @@ -147,9 +147,11 @@ export default defineConfig({ |--------|-----------| | ESM | `.mjs` or `.js` (with `"type": "module"`) | | CJS | `.cjs` or `.js` (without `"type": "module"`) | -| IIFE | `.global.js` | +| IIFE | `.iife.js` | | UMD | `.umd.js` | +For `tsup`-style IIFE filenames such as `index.global.js`, set `outputOptions.entryFileNames`. `outExtensions` customizes extensions or suffixes but does not remove `.iife` or `.umd`. + ### Customize Extensions Use `outExtensions` to override: diff --git a/src/config/options.ts b/src/config/options.ts index e9a8fc73c..138b4164f 100644 --- a/src/config/options.ts +++ b/src/config/options.ts @@ -103,6 +103,8 @@ export async function resolveUserConfig( globImport = true, css, injectStyle, + outExtension, + outExtensions, fixedExtension = platform === 'node', devtools = false, write = true, @@ -222,6 +224,18 @@ export async function resolveUserConfig( } } + if (outExtension) { + if (outExtensions) { + throw new TypeError( + '`outExtension` is deprecated. Cannot be used with `outExtensions`', + ) + } + logger.warn( + `${blue`outExtension`} is deprecated. Use ${blue`outExtensions`} instead.`, + ) + outExtensions = outExtension + } + envPrefix = toArray(envPrefix) if (envPrefix.includes('')) { logger.warn( @@ -299,9 +313,12 @@ export async function resolveUserConfig( } } + const configUserConfig = { ...userConfig } + delete configUserConfig.outExtension + /// keep-sorted const config: Omit = { - ...userConfig, + ...configUserConfig, alias, attw, cjsDefault, @@ -326,6 +343,7 @@ export async function resolveUserConfig( nameLabel, nodeProtocol, outDir, + outExtensions, pkg, platform, plugins, diff --git a/src/config/types.ts b/src/config/types.ts index 560ed0ddb..6a48f1c4c 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -488,6 +488,11 @@ export interface UserConfig { */ outExtensions?: OutExtensionFactory + /** + * @deprecated Use {@linkcode outExtensions} instead. + */ + outExtension?: OutExtensionFactory + /** * If enabled, appends hash to chunk filenames. * @default true @@ -722,6 +727,7 @@ export type ResolvedConfig = Overwrite< | 'bundle' // deprecated | 'injectStyle' // deprecated, merged to `css` | 'removeNodeProtocol' // deprecated + | 'outExtension' // deprecated | 'external' // deprecated, merged to `deps` | 'noExternal' // deprecated, merged to `deps` | 'inlineOnly' // deprecated, merged to `deps` diff --git a/tests/__snapshots__/deprecated-custom-extension.snap.md b/tests/__snapshots__/deprecated-custom-extension.snap.md new file mode 100644 index 000000000..4370b7014 --- /dev/null +++ b/tests/__snapshots__/deprecated-custom-extension.snap.md @@ -0,0 +1,9 @@ +## index.some.mjs + +```mjs +//#region index.ts +var deprecated_custom_extension_default = 10; +//#endregion +export { deprecated_custom_extension_default as default }; + +``` diff --git a/tests/e2e.test.ts b/tests/e2e.test.ts index a0990144a..b9dcb0f43 100644 --- a/tests/e2e.test.ts +++ b/tests/e2e.test.ts @@ -152,6 +152,53 @@ test('custom extension', async (context) => { `) }) +test('deprecated custom extension', async (context) => { + const files = { + 'index.ts': `export default 10`, + } + const warn = vi.fn() + const { outputFiles } = await testBuild({ + context, + files, + options: { + customLogger: { + level: 'info', + info: vi.fn(), + warn, + warnOnce: vi.fn(), + error: vi.fn(), + success: vi.fn(), + clearScreen: vi.fn(), + }, + outExtension: () => ({ js: '.some.mjs' }), + }, + }) + expect(warn).toHaveBeenCalledWith(expect.stringContaining('outExtension')) + expect(outputFiles).toMatchInlineSnapshot(` + [ + "index.some.mjs", + ] + `) +}) + +test('deprecated custom extension conflict', async (context) => { + const files = { + 'index.ts': `export default 10`, + } + await expect( + testBuild({ + context, + files, + options: { + outExtension: () => ({ js: '.old.mjs' }), + outExtensions: () => ({ js: '.new.mjs' }), + }, + }), + ).rejects.toThrow( + '`outExtension` is deprecated. Cannot be used with `outExtensions`', + ) +}) + test('custom extension with empty string', async (context) => { const files = { 'index.ts': `export default 10`, From f4d5663c21ece7864f3254d4e3324a6c4354551e Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 15 May 2026 13:17:58 +0000 Subject: [PATCH 2/3] [autofix.ci] apply automated fixes --- __snapshots__/tsnapi/config.snapshot.d.ts | 1 + __snapshots__/tsnapi/index.snapshot.d.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/__snapshots__/tsnapi/config.snapshot.d.ts b/__snapshots__/tsnapi/config.snapshot.d.ts index a1ea9e046..8befb7b40 100644 --- a/__snapshots__/tsnapi/config.snapshot.d.ts +++ b/__snapshots__/tsnapi/config.snapshot.d.ts @@ -43,6 +43,7 @@ export interface UserConfig { bundle?: boolean; fixedExtension?: boolean; outExtensions?: OutExtensionFactory; + outExtension?: OutExtensionFactory; hash?: boolean; cjsDefault?: boolean; outputOptions?: OutputOptions | ((_: OutputOptions, _: NormalizedFormat, _: { diff --git a/__snapshots__/tsnapi/index.snapshot.d.ts b/__snapshots__/tsnapi/index.snapshot.d.ts index 0c9453826..e6fa95e88 100644 --- a/__snapshots__/tsnapi/index.snapshot.d.ts +++ b/__snapshots__/tsnapi/index.snapshot.d.ts @@ -171,6 +171,7 @@ export interface UserConfig { bundle?: boolean; fixedExtension?: boolean; outExtensions?: OutExtensionFactory; + outExtension?: OutExtensionFactory; hash?: boolean; cjsDefault?: boolean; outputOptions?: OutputOptions | ((_: OutputOptions, _: NormalizedFormat, _: { @@ -222,7 +223,7 @@ export type NoExternalFn = (_: string, _: string | undefined) => boolean | null export type NormalizedFormat = InternalModuleFormat; export type OutExtensionFactory = (_: OutExtensionContext) => OutExtensionObject | undefined; export type PackageType = "module" | "commonjs" | undefined; -export type ResolvedConfig = Overwrite, "globalName" | "inputOptions" | "outputOptions" | "minify" | "define" | "alias" | "onSuccess" | "outExtensions" | "hooks" | "copy" | "loader" | "name" | "banner" | "footer" | "checks" | "css">, { +export type ResolvedConfig = Overwrite, "globalName" | "inputOptions" | "outputOptions" | "minify" | "define" | "alias" | "onSuccess" | "outExtensions" | "hooks" | "copy" | "loader" | "name" | "banner" | "footer" | "checks" | "css">, { entry: Record; rawEntry?: TsdownInputOption; nameLabel: string | undefined; From e45a242aa33bd459ce7f9121ad035af35339dd1d Mon Sep 17 00:00:00 2001 From: Kevin Deng Date: Fri, 15 May 2026 22:24:57 +0900 Subject: [PATCH 3/3] docs: clarify custom IIFE filename guidance --- docs/options/output-format.md | 2 +- docs/zh-CN/options/output-format.md | 2 +- .../tsdown-migrate/references/guide-differences-detailed.md | 2 +- skills/tsdown/references/option-output-directory.md | 2 +- skills/tsdown/references/option-output-format.md | 2 +- src/config/options.ts | 5 +---- 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/docs/options/output-format.md b/docs/options/output-format.md index 30ec16117..bf0547541 100644 --- a/docs/options/output-format.md +++ b/docs/options/output-format.md @@ -33,7 +33,7 @@ tsdown --format iife > **CJS is in maintenance-only mode.** Since the ecosystem is transitioning to ESM and Node.js now supports `require(esm)`, `tsdown`'s CJS-specific features (such as [`cjsDefault`](./cjs-default.md)) are kept for compatibility but will not be further enhanced or optimized. New libraries are encouraged to publish ESM-only. > [!NOTE] -> IIFE and UMD outputs include the format in their filenames by default, such as `index.iife.js` and `index.umd.js`. If you need a custom full filename pattern, such as the `tsup`-style `index.global.js`, set `outputOptions.entryFileNames`. +> IIFE and UMD outputs include the format in their filenames by default, such as `index.iife.js` and `index.umd.js`. If you need a custom full filename pattern, set `outputOptions.entryFileNames`. ## Overriding Configuration by Format diff --git a/docs/zh-CN/options/output-format.md b/docs/zh-CN/options/output-format.md index 47ff5c035..d010eb0d4 100644 --- a/docs/zh-CN/options/output-format.md +++ b/docs/zh-CN/options/output-format.md @@ -33,7 +33,7 @@ tsdown --format iife > **CJS 处于仅维护模式。** 由于生态系统正在向 ESM 迁移,且 Node.js 已支持 `require(esm)`,`tsdown` 中 CJS 专属的功能(例如 [`cjsDefault`](./cjs-default.md))仅保留以确保兼容性,不会再进一步增强或优化。建议新库直接发布为 ESM-only。 > [!NOTE] -> IIFE 和 UMD 输出默认会在文件名中包含格式片段,例如 `index.iife.js` 和 `index.umd.js`。如果需要自定义完整文件名模式,例如 `tsup` 风格的 `index.global.js`,请设置 `outputOptions.entryFileNames`。 +> IIFE 和 UMD 输出默认会在文件名中包含格式片段,例如 `index.iife.js` 和 `index.umd.js`。如果需要自定义完整文件名模式,请设置 `outputOptions.entryFileNames`。 ## 按格式覆盖配置 diff --git a/skills/tsdown-migrate/references/guide-differences-detailed.md b/skills/tsdown-migrate/references/guide-differences-detailed.md index 70ca64261..67889bdd6 100644 --- a/skills/tsdown-migrate/references/guide-differences-detailed.md +++ b/skills/tsdown-migrate/references/guide-differences-detailed.md @@ -64,7 +64,7 @@ These tsup options still work in tsdown but emit deprecation warnings. They will ### Output Filename Differences -For IIFE builds, `tsdown` emits `[name].iife.js`; `tsup` commonly emitted `[name].global.js`. `outExtensions` customizes extensions or suffixes, but it does not remove `.iife` or `.umd`. Use `outputOptions.entryFileNames` for full filename patterns such as `[name].global.js`. +For IIFE builds, `tsdown` emits `[name].iife.js`; `tsup` commonly emitted `[name].global.js`. `outExtensions` customizes extensions or suffixes, but it does not remove `.iife` or `.umd`. Use `outputOptions.entryFileNames` for full filename patterns. ### Not Supported diff --git a/skills/tsdown/references/option-output-directory.md b/skills/tsdown/references/option-output-directory.md index bcc0e9769..ff09cfea5 100644 --- a/skills/tsdown/references/option-output-directory.md +++ b/skills/tsdown/references/option-output-directory.md @@ -125,7 +125,7 @@ export default defineConfig({ | `iife` | `.iife.js` | `.iife.js` | | `umd` | `.umd.js` | `.umd.js` | -For IIFE/UMD builds, `outExtensions` customizes extensions or suffixes but does not remove the built-in `.iife` or `.umd` segment. Use `outputOptions.entryFileNames` for custom full filename patterns such as `[name].global.js`. +For IIFE/UMD builds, `outExtensions` customizes extensions or suffixes but does not remove the built-in `.iife` or `.umd` segment. Use `outputOptions.entryFileNames` for custom full filename patterns. ### ESM with .js Extension diff --git a/skills/tsdown/references/option-output-format.md b/skills/tsdown/references/option-output-format.md index a3538bf86..6f9852e39 100644 --- a/skills/tsdown/references/option-output-format.md +++ b/skills/tsdown/references/option-output-format.md @@ -150,7 +150,7 @@ export default defineConfig({ | IIFE | `.iife.js` | | UMD | `.umd.js` | -For `tsup`-style IIFE filenames such as `index.global.js`, set `outputOptions.entryFileNames`. `outExtensions` customizes extensions or suffixes but does not remove `.iife` or `.umd`. +For custom IIFE filenames, set `outputOptions.entryFileNames`. `outExtensions` customizes extensions or suffixes but does not remove `.iife` or `.umd`. ### Customize Extensions diff --git a/src/config/options.ts b/src/config/options.ts index 138b4164f..6d6b9e396 100644 --- a/src/config/options.ts +++ b/src/config/options.ts @@ -313,12 +313,9 @@ export async function resolveUserConfig( } } - const configUserConfig = { ...userConfig } - delete configUserConfig.outExtension - /// keep-sorted const config: Omit = { - ...configUserConfig, + ...userConfig, alias, attw, cjsDefault,