diff --git a/e2e/cases/dts/bundle/bundleName.config.ts b/e2e/cases/dts/bundle/bundleName.config.ts new file mode 100644 index 000000000..6cdca50fa --- /dev/null +++ b/e2e/cases/dts/bundle/bundleName.config.ts @@ -0,0 +1,18 @@ +import { generateBundleCjsConfig, generateBundleEsmConfig } from '@e2e/helper'; +import { defineConfig } from '@rslib/core'; + +export default defineConfig({ + lib: [ + generateBundleEsmConfig(__dirname, { + dts: { + bundle: true, + }, + }), + generateBundleCjsConfig(__dirname), + ], + source: { + entry: { + bundleName: './src/index.ts', + }, + }, +}); diff --git a/e2e/cases/dts/index.test.ts b/e2e/cases/dts/index.test.ts index 08a8f5ae2..08e0a903d 100644 --- a/e2e/cases/dts/index.test.ts +++ b/e2e/cases/dts/index.test.ts @@ -90,7 +90,7 @@ describe('dts when bundle: true', () => { 'dts', ); - expect(entryFiles.esm).toEqual('./dist/esm/index.d.ts'); + expect(entryFiles.esm).toEqual('./dist/esm/main.d.ts'); expect(entries).toMatchSnapshot(); }); @@ -113,7 +113,7 @@ describe('dts when bundle: true', () => { 'dts', ); - expect(entryFiles.esm).toEqual('./dist/custom/index.d.ts'); + expect(entryFiles.esm).toEqual('./dist/custom/main.d.ts'); }); test('abortOnError: false', async () => { @@ -135,6 +135,17 @@ describe('dts when bundle: true', () => { 'dts', ); - expect(entryFiles.cjs).toEqual('./dist/cjs/index.d.cts'); + expect(entryFiles.cjs).toEqual('./dist/cjs/main.d.cts'); + }); + + test('bundleName -- set source.entry', async () => { + const fixturePath = join(__dirname, 'bundle'); + const { entryFiles } = await buildAndGetResults( + fixturePath, + 'bundleName.config.ts', + 'dts', + ); + + expect(entryFiles.esm).toEqual('./dist/esm/bundleName.d.ts'); }); }); diff --git a/packages/plugin-dts/src/apiExtractor.ts b/packages/plugin-dts/src/apiExtractor.ts index a92e1a00a..e0106e153 100644 --- a/packages/plugin-dts/src/apiExtractor.ts +++ b/packages/plugin-dts/src/apiExtractor.ts @@ -6,6 +6,7 @@ import { } from '@microsoft/api-extractor'; import { logger } from '@rsbuild/core'; import color from 'picocolors'; +import type { DtsEntry } from 'src'; import { getTimeCost } from './utils'; export type BundleOptions = { @@ -13,7 +14,7 @@ export type BundleOptions = { cwd: string; outDir: string; dtsExtension: string; - entry?: string; + dtsEntry: DtsEntry; tsconfigPath?: string; }; @@ -23,7 +24,10 @@ export async function bundleDts(options: BundleOptions): Promise { cwd, outDir, dtsExtension, - entry = 'index.d.ts', + dtsEntry = { + name: 'index', + path: 'index.d.ts', + }, tsconfigPath = 'tsconfig.json', } = options; try { @@ -31,10 +35,11 @@ export async function bundleDts(options: BundleOptions): Promise { const untrimmedFilePath = join( cwd, relative(cwd, outDir), - `index${dtsExtension}`, + `${dtsEntry.name}${dtsExtension}`, ); + const mainEntryPointFilePath = dtsEntry.path!; const internalConfig = { - mainEntryPointFilePath: entry, + mainEntryPointFilePath, // TODO: use !externals // bundledPackages: [], dtsRollup: { diff --git a/packages/plugin-dts/src/dts.ts b/packages/plugin-dts/src/dts.ts index d6babe2e2..3f1e6b770 100644 --- a/packages/plugin-dts/src/dts.ts +++ b/packages/plugin-dts/src/dts.ts @@ -10,7 +10,7 @@ export async function generateDts(data: DtsGenOptions): Promise { const { bundle, distPath, - entryPath, + dtsEntry, tsconfigPath, name, cwd, @@ -37,6 +37,7 @@ export async function generateDts(data: DtsGenOptions): Promise { }; const declarationDir = getDeclarationDir(bundle!, distPath); + const { name: entryName, path: entryPath } = dtsEntry; let entry = ''; if (bundle === true && entryPath) { @@ -59,7 +60,10 @@ export async function generateDts(data: DtsGenOptions): Promise { name, cwd, outDir, - entry, + dtsEntry: { + name: entryName, + path: entry, + }, tsconfigPath, dtsExtension, }); @@ -99,6 +103,7 @@ process.on('message', async (data: DtsGenOptions) => { try { await generateDts(data); } catch (e) { + logger.error(e); process.send!('error'); process.exit(1); } diff --git a/packages/plugin-dts/src/index.ts b/packages/plugin-dts/src/index.ts index 648c506bd..1ac77743c 100644 --- a/packages/plugin-dts/src/index.ts +++ b/packages/plugin-dts/src/index.ts @@ -1,6 +1,7 @@ import { fork } from 'node:child_process'; import { extname, join } from 'node:path'; import { type RsbuildPlugin, logger } from '@rsbuild/core'; +import { processSourceEntry } from './utils'; export type PluginDtsOptions = { bundle?: boolean; @@ -9,11 +10,16 @@ export type PluginDtsOptions = { dtsExtension?: string; }; +export type DtsEntry = { + name?: string; + path?: string; +}; + export type DtsGenOptions = PluginDtsOptions & { name: string; cwd: string; isWatch: boolean; - entryPath?: string; + dtsEntry: DtsEntry; tsconfigPath?: string; }; @@ -54,10 +60,16 @@ export const pluginDts = (options: PluginDtsOptions): RsbuildPlugin => ({ stdio: 'inherit', }); + // TODO: @microsoft/api-extractor only support single entry to bundle DTS + // use first element of Record type entry config + const dtsEntry = processSourceEntry( + options.bundle!, + config.source?.entry, + ); + const dtsGenOptions: DtsGenOptions = { ...options, - // TODO: temporarily use main as dts entry, only accept single entry - entryPath: config.source?.entry?.main as string, + dtsEntry, tsconfigPath: config.source.tsconfigPath, name: environment.name, cwd: api.context.rootPath, diff --git a/packages/plugin-dts/src/utils.ts b/packages/plugin-dts/src/utils.ts index 320adef90..942006552 100644 --- a/packages/plugin-dts/src/utils.ts +++ b/packages/plugin-dts/src/utils.ts @@ -1,8 +1,9 @@ import fs from 'node:fs'; import path from 'node:path'; -import { logger } from '@rsbuild/core'; +import { type RsbuildConfig, logger } from '@rsbuild/core'; import fg from 'fast-glob'; import color from 'picocolors'; +import type { DtsEntry } from 'src'; import * as ts from 'typescript'; export function loadTsconfig(tsconfigPath: string): ts.ParsedCommandLine { @@ -70,3 +71,29 @@ export async function processDtsFiles( } } } + +export function processSourceEntry( + bundle: boolean, + entryConfig: NonNullable['entry'], +): DtsEntry { + if (!bundle) { + return { + name: undefined, + path: undefined, + }; + } + + if ( + entryConfig && + Object.values(entryConfig).every((val) => typeof val === 'string') + ) { + return { + name: Object.keys(entryConfig)[0] as string, + path: Object.values(entryConfig)[0] as string, + }; + } + + throw new Error( + '@microsoft/api-extractor only support single entry of Record type to bundle DTS, please check your entry config.', + ); +}