Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ test-results
.env.local
.env.*.local
.rslib/**/*
!dist-path/
1 change: 1 addition & 0 deletions packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,7 @@ const composeDtsConfig = async (
banner: banner?.dts,
footer: footer?.dts,
redirect: redirect?.dts,
experiments: dts?.experiments,
}),
],
};
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,19 @@ export type Dts =
* @see {@link https://rslib.rs/config/lib/dts#dtsalias}
*/
alias?: Record<string, string>;
/**
* [Experimental] Whether to enable experimental features.
* @defaultValue `{}`
* @see {@link https://rslib.rs/config/lib/dts#dtsexperiments}
*/
experiments?: {
/**
* [Experimental] Whether to generate declaration files with `tsgo`.
* @defaultValue `false`
* @see {@link https://rslib.rs/config/lib/dts#dtsexperimentstsgo}
*/
tsgo?: boolean;
};
}
| boolean;

Expand Down
38 changes: 38 additions & 0 deletions packages/plugin-dts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ pluginDts({
});
```

> When [experiments.tsgo](#experimentstsgo) is enabled, if the project also enables [build](#build) or emits declaration files with different extensions to the same directory, `dtsExtension` may not work correctly.

### alias

- **Type:** `Record<string, string>`
Expand Down Expand Up @@ -280,6 +282,42 @@ import { foo } from './foo.mjs'; // expected output of './dist/bar.d.mts'

- When set to `false`, the file extension will remain unchanged from the original import path in the rewritten import path of the output file (regardless of whether it is specified or specified as any value).

### experiments

- **Type:** `{ tsgo?: boolean }`
- **Default:** `{}`

Whether to enable experimental features.

#### experiments.tsgo

- **Type:** `boolean`
- **Default:** `false`

Whether to generate declaration files with [tsgo](https://github.com/microsoft/typescript-go).

To enable this option, you need to:

1. Install [@typescript/native-preview](https://www.npmjs.com/package/@typescript/native-preview) as a development dependency.

```bash
npm add @typescript/native-preview -D
```

> `@typescript/native-preview` requires Node.js 20.6.0 or higher.

2. Set `experiments.tsgo` to `true`.

```js
pluginDts({
experiments: {
tsgo: true,
},
});
```

> `tsgo` can provide faster generation of declaration files, especially for large projects. However, since `tsgo` is still experimental, there may be unresolved issues or limitations. Therefore, please make sure to thoroughly test it in your project before enabling this option.

## Contributing

Please read the [Contributing Guide](https://github.com/web-infra-dev/rslib/blob/main/CONTRIBUTING.md).
Expand Down
5 changes: 5 additions & 0 deletions packages/plugin-dts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,24 @@
"@microsoft/api-extractor": "^7.52.11",
"@rsbuild/core": "~1.5.3",
"@rslib/tsconfig": "workspace:*",
"@typescript/native-preview": "7.0.0-dev.20250904.1",
"rsbuild-plugin-publint": "^0.3.3",
"rslib": "npm:@rslib/[email protected]",
"typescript": "^5.9.2"
},
"peerDependencies": {
"@microsoft/api-extractor": "^7",
"@rsbuild/core": "1.x",
"@typescript/native-preview": "7.x",
"typescript": "^5"
},
"peerDependenciesMeta": {
"@microsoft/api-extractor": {
"optional": true
},
"@typescript/native-preview": {
"optional": true
},
"typescript": {
"optional": true
}
Expand Down
21 changes: 17 additions & 4 deletions packages/plugin-dts/src/dts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
import { logger } from '@rsbuild/core';
import color from 'picocolors';
import type { DtsEntry, DtsGenOptions } from './index';
import { emitDts } from './tsc';
import {
calcLongestCommonPath,
ensureTempDeclarationDir,
Expand Down Expand Up @@ -136,7 +135,11 @@ export async function generateDts(data: DtsGenOptions): Promise<void> {
path: true,
extension: false,
},
experiments = {
tsgo: false,
},
} = data;
const { tsgo } = experiments;
if (!isWatch) {
logger.start(`generating declaration files... ${color.dim(`(${name})`)}`);
}
Expand Down Expand Up @@ -248,7 +251,11 @@ export async function generateDts(data: DtsGenOptions): Promise<void> {
}
};

await emitDts(
const emitDts = tsgo
? await import('./tsgo').then((mod) => mod.emitDtsTsgo)
: await import('./tsc').then((mod) => mod.emitDtsTsc);

const hasError = await emitDts(
{
name,
cwd,
Expand All @@ -268,8 +275,14 @@ export async function generateDts(data: DtsGenOptions): Promise<void> {
build,
);

if (!isWatch) {
await bundleDtsIfNeeded();
if (tsgo) {
if (!hasError) {
await bundleDtsIfNeeded();
}
} else {
if (!isWatch) {
await bundleDtsIfNeeded();
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion packages/plugin-dts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export type PluginDtsOptions = {
banner?: string;
footer?: string;
redirect?: DtsRedirect;
experiments?: {
tsgo?: boolean;
};
};

export type DtsEntry = {
Expand Down Expand Up @@ -93,14 +96,16 @@ export const pluginDts = (options: PluginDtsOptions = {}): RsbuildPlugin => ({
options.redirect.path = options.redirect.path ?? true;
options.redirect.extension = options.redirect.extension ?? false;
options.alias = options.alias ?? {};
options.experiments = options.experiments ?? {};
options.experiments.tsgo = options.experiments.tsgo ?? false;

const dtsPromises: Promise<TaskResult>[] = [];
let promisesResult: TaskResult[] = [];
let childProcesses: ChildProcess[] = [];

api.onBeforeEnvironmentCompile(
async ({ isWatch, isFirstCompile, environment }) => {
if (!isFirstCompile) {
if (!isFirstCompile && !options.experiments?.tsgo) {
return;
}

Expand Down
73 changes: 31 additions & 42 deletions packages/plugin-dts/src/tsc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import { logger } from '@rsbuild/core';
import color from 'picocolors';
import ts from 'typescript';
import type { DtsRedirect } from './index';
import { getTimeCost, processDtsFiles } from './utils';
import {
getTimeCost,
processDtsFiles,
renameDtsFile,
updateDeclarationMapContent,
} from './utils';

const logPrefixTsc = color.dim('[tsc]');

Expand Down Expand Up @@ -75,7 +80,7 @@ async function handleDiagnosticsAndProcessFiles(
}
}

export async function emitDts(
export async function emitDtsTsc(
options: EmitDtsOptions,
onComplete: (isSuccess: boolean) => void,
bundle = false,
Expand Down Expand Up @@ -174,45 +179,17 @@ export async function emitDts(
}
};

const renameDtsFile = (fileName: string): string => {
if (bundle) {
return fileName;
}

if (fileName.endsWith('.d.ts.map')) {
return fileName.replace(/\.d\.ts\.map$/, `${dtsExtension}.map`);
}

return fileName.replace(/\.d\.ts$/, dtsExtension);
};

const updateDeclarationMapContent = (
fileName: string,
content: string,
): string => {
if (bundle || !compilerOptions.declarationMap) {
return content;
}

if (fileName.endsWith('.d.ts')) {
return content.replace(
/(\/\/# sourceMappingURL=.+)\.d\.ts\.map/g,
`$1${dtsExtension}.map`,
);
}

if (fileName.endsWith('.d.ts.map')) {
return content.replace(/("file":"[^"]*)\.d\.ts"/g, `$1${dtsExtension}"`);
}

return content;
};

const system: ts.System = {
...ts.sys,
writeFile: (fileName, contents, writeByteOrderMark) => {
const newFileName = renameDtsFile(fileName);
const newContents = updateDeclarationMapContent(fileName, contents);
const newFileName = renameDtsFile(fileName, dtsExtension, bundle);
const newContents = updateDeclarationMapContent(
fileName,
contents,
dtsExtension,
bundle,
compilerOptions.declarationMap,
);
ts.sys.writeFile(newFileName, newContents, writeByteOrderMark);
},
};
Expand All @@ -232,8 +209,14 @@ export async function emitDts(
onError,
sourceFiles,
) => {
const newFileName = renameDtsFile(fileName);
const newContents = updateDeclarationMapContent(fileName, contents);
const newFileName = renameDtsFile(fileName, dtsExtension, bundle);
const newContents = updateDeclarationMapContent(
fileName,
contents,
dtsExtension,
bundle,
compilerOptions.declarationMap,
);
originHost.writeFile(
newFileName,
newContents,
Expand Down Expand Up @@ -285,8 +268,14 @@ export async function emitDts(
onError,
sourceFiles,
) => {
const newFileName = renameDtsFile(fileName);
const newContents = updateDeclarationMapContent(fileName, contents);
const newFileName = renameDtsFile(fileName, dtsExtension, bundle);
const newContents = updateDeclarationMapContent(
fileName,
contents,
dtsExtension,
bundle,
compilerOptions.declarationMap,
);
originHost.writeFile(
newFileName,
newContents,
Expand Down
Loading
Loading