这是indexloc提供的服务,不要输入任何密码
Skip to content

fix: outExtension for generating dts files #1235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ When you use legacy TypeScript decorator by enabling `emitDecoratorMetadata` in
decorators. In this case, you can give extra swc configuration in the `tsup.config.ts` file.

For example, if you have to define `useDefineForClassFields`, you can do that as follows:

```ts
import { defineConfig } from 'tsup'

Expand All @@ -626,10 +627,10 @@ export default defineConfig({
swc: {
jsc: {
transform: {
useDefineForClassFields: true
}
}
}
useDefineForClassFields: true,
},
},
},
})
```

Expand All @@ -648,9 +649,9 @@ Note: some SWC options cannot be configured:
"keepClassNames": true,
"target": "es2022"
}
```
```

You can also define a custom `.swcrc` configuration file. Just set `swcrc` to `true`
You can also define a custom `.swcrc` configuration file. Just set `swcrc` to `true`
in `tsup.config.ts` to allow SWC plugin to discover automatically your custom swc config file.

```ts
Expand All @@ -662,8 +663,8 @@ export default defineConfig({
sourcemap: true,
clean: true,
swc: {
swcrc: true
}
swcrc: true,
},
})
```

Expand Down
6 changes: 5 additions & 1 deletion src/api-extractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,11 @@ async function rollupDtsFiles(
const declarationDir = ensureTempDeclarationDir()
const outDir = options.outDir || 'dist'
const pkg = await loadPkg(process.cwd())
const dtsExtension = defaultOutExtension({ format, pkgType: pkg.type }).dts

const dtsExtension =
options.outputExtensionMap.get(format)?.dts ||
defaultOutExtension({ format, pkgType: pkg.type }).dts

const tsconfig = options.tsconfig || 'tsconfig.json'

let dtsInputFilePath = path.join(
Expand Down
5 changes: 4 additions & 1 deletion src/esbuild/swc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import type { Logger } from '../log'

export type SwcPluginConfig = { logger: Logger } & Options

export const swcPlugin = ({ logger, ...swcOptions }: SwcPluginConfig): Plugin => {
export const swcPlugin = ({
logger,
...swcOptions
}: SwcPluginConfig): Plugin => {
return {
name: 'swc',

Expand Down
16 changes: 12 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
removeFiles,
resolveExperimentalDtsConfig,
resolveInitialExperimentalDtsConfig,
resolveOutputExtensionMap,
slash,
} from './utils'
import { createLogger, setSilent } from './log'
Expand Down Expand Up @@ -77,14 +78,17 @@ const normalizeOptions = async (
...optionsOverride,
}

const formats =
typeof _options.format === 'string'
? [_options.format]
: _options.format || ['cjs']

const options: Partial<NormalizedOptions> = {
outDir: 'dist',
removeNodeProtocol: true,
..._options,
format:
typeof _options.format === 'string'
? [_options.format as Format]
: _options.format || ['cjs'],
format: formats,

dts:
typeof _options.dts === 'boolean'
? _options.dts
Expand Down Expand Up @@ -161,6 +165,10 @@ const normalizeOptions = async (
options.target = 'node16'
}

options.outputExtensionMap = await resolveOutputExtensionMap(
options as NormalizedOptions,
)

return options as NormalizedOptions
}

Expand Down
13 changes: 11 additions & 2 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,8 @@ export type Options = {
* @default true
*/
removeNodeProtocol?: boolean
swc?: SwcPluginConfig;

swc?: SwcPluginConfig
}

export interface NormalizedExperimentalDtsConfig {
Expand All @@ -275,5 +275,14 @@ export type NormalizedOptions = Omit<
tsconfigResolvePaths: Record<string, string[]>
tsconfigDecoratorMetadata?: boolean
format: Format[]

/**
* Custom file extension per each
* {@linkcode Format | module format}.
*
* @since 8.6.0
*/
outputExtensionMap: Map<Format, OutExtensionObject>

swc?: SwcPluginConfig
}
2 changes: 1 addition & 1 deletion src/rollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ const getRollupConfig = async (
},
outputConfig: options.format.map((format): OutputOptions => {
const outputExtension =
options.outExtension?.({ format, options, pkgType: pkg.type }).dts ||
options.outputExtensionMap.get(format)?.dts ||
defaultOutExtension({ format, pkgType: pkg.type }).dts
return {
dir: options.outDir || 'dist',
Expand Down
38 changes: 38 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import resolveFrom from 'resolve-from'
import type { InputOption } from 'rollup'
import strip from 'strip-json-comments'
import { glob } from 'tinyglobby'
import { loadPkg } from './load.js'
import type {
Entry,
Format,
Expand Down Expand Up @@ -422,3 +423,40 @@ export const resolveInitialExperimentalDtsConfig = async (
: await resolveEntryPaths(experimentalDts.entry),
}
}

/**
* Resolves the
* {@linkcode NormalizedOptions.outputExtensionMap | output extension map}
* for each specified {@linkcode Format | format}
* in the provided {@linkcode options}.
*
* @param options - The normalized options containing format and output extension details.
* @returns A {@linkcode Promise | promise} that resolves to a {@linkcode Map}, where each key is a {@linkcode Format | format} and each value is an object containing the resolved output extensions for both `js` and `dts` files.
*
* @internal
*/
export const resolveOutputExtensionMap = async (
options: NormalizedOptions,
): Promise<NormalizedOptions['outputExtensionMap']> => {
const pkg = await loadPkg(process.cwd())

const formatOutExtension = new Map(
options.format.map((format) => {
const outputExtensions = options.outExtension?.({
format,
options,
pkgType: pkg.type,
})

return [
format,
{
...defaultOutExtension({ format, pkgType: pkg.type }),
...(outputExtensions || {}),
},
] as const
}),
)

return formatOutExtension
}
55 changes: 55 additions & 0 deletions test/dts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,3 +480,58 @@ test('declaration files with multiple entrypoints #316', async () => {
'dist/bar/index.d.ts',
).toMatchSnapshot()
})

test('custom dts output extension', async ({ expect, task }) => {
const { outFiles } = await run(
getTestName(),
{
'src/types.ts': `export type Person = { name: string }`,
'src/index.ts': `export const foo = [1, 2, 3]\nexport type { Person } from './types'`,
'tsup.config.ts': `export default {
name: '${task.name}',
entry: { index: 'src/index.ts' },
dts: true,
format: ['esm', 'cjs'],
outExtension({ format }) {
return {
js: format === 'esm' ? '.cjs' : '.mjs',
dts: format === 'esm' ? '.d.cts' : '.d.mts',
}
},
}`,
'package.json': JSON.stringify(
{
name: 'custom-dts-output-extension',
description: task.name,
type: 'module',
},
null,
2,
),
'tsconfig.json': JSON.stringify(
{
compilerOptions: {
outDir: './dist',
rootDir: './src',
moduleResolution: 'Bundler',
module: 'ESNext',
strict: true,
skipLibCheck: true,
},
include: ['src'],
},
null,
2,
),
},
{
entry: [],
},
)
expect(outFiles).toStrictEqual([
'index.cjs',
'index.d.cts',
'index.d.mts',
'index.mjs',
])
})
61 changes: 61 additions & 0 deletions test/experimental-dts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -604,3 +604,64 @@ test('experimentalDts.entry can be a string of glob pattern', async ({
),
)
})

test('custom outExtension works with experimentalDts', async ({
expect,
task,
}) => {
const { outFiles } = await run(
getTestName(),
{
'src/types.ts': `export type Person = { name: string }`,
'src/index.ts': `export const foo = [1, 2, 3]\nexport type { Person } from './types'`,
'tsup.config.ts': `export default {
name: '${task.name}',
entry: { index: 'src/index.ts' },
format: ['esm', 'cjs'],
experimentalDts: true,
outExtension({ format }) {
return {
js: format === 'cjs' ? '.cjs' : '.mjs',
dts: format === 'cjs' ? '.d.cts' : '.d.mts',
}
},
}`,
'package.json': JSON.stringify(
{
name: 'custom-dts-output-extension-with-experimental-dts',
description: task.name,
type: 'module',
},
null,
2,
),
'tsconfig.json': JSON.stringify(
{
compilerOptions: {
outDir: './dist',
rootDir: './src',
moduleResolution: 'Bundler',
module: 'ESNext',
strict: true,
skipLibCheck: true,
},
include: ['src'],
},
null,
2,
),
},
{
entry: [],
},
)

expect(outFiles).toStrictEqual([
'_tsup-dts-rollup.d.cts',
'_tsup-dts-rollup.d.mts',
'index.cjs',
'index.d.cts',
'index.d.mts',
'index.mjs',
])
})
4 changes: 2 additions & 2 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ test('onSuccess: use a function from config file', async () => {
await new Promise((resolve) => {
setTimeout(() => {
console.log('world')
resolve('')
resolve('')
}, 1_000)
})
}
Expand Down Expand Up @@ -601,7 +601,7 @@ test('use rollup for treeshaking --format cjs', async () => {
}`,
'input.tsx': `
import ReactSelect from 'react-select'

export const Component = (props: {}) => {
return <ReactSelect {...props} />
};
Expand Down
2 changes: 1 addition & 1 deletion vitest.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ export default defineConfig({
test: {
testTimeout: 50000,
globalSetup: 'vitest-global.ts',
include: ["test/*.test.ts", "src/**/*.test.ts"]
include: ['test/*.test.ts', 'src/**/*.test.ts'],
},
})