Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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,
tsgo: dts?.tsgo,
}),
],
};
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ export type Dts =
* @see {@link https://rslib.rs/config/lib/dts#dtsalias}
*/
alias?: Record<string, string>;
/**
* [Experimental] Whether to generate declaration files with `tsgo`.
* @defaultValue `false`
* @see {@link https://rslib.rs/config/lib/dts#dtstsgo}
*/
tsgo?: boolean;
}
| boolean;

Expand Down
37 changes: 37 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 [tsgo](#tsgo) 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,41 @@ 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).

### tsgo

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

Whether to generate declaration files with [tsgo](https://github.com/microsoft/typescript-go), which can provide faster generation of declaration files, especially for large projects.

> This feature is currently an **experimental feature**. Since tsgo is still in the **experimental stage**, there may be some bugs and unresolved issues or limitations. So, make sure to fully test it in your project before enabling this option.

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 `tsgo` to `true`.

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

3. In order to ensure the consistency of local development, you need to install the corresponding [VS Code Preview Extension](https://marketplace.visualstudio.com/items?itemName=TypeScriptTeam.native-preview) and add the following configuration in the VS Code settings:

```json
{
"typescript.experimental.useTsgo": true
}
```

## 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
18 changes: 14 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,6 +135,7 @@ export async function generateDts(data: DtsGenOptions): Promise<void> {
path: true,
extension: false,
},
tsgo,
} = data;
if (!isWatch) {
logger.start(`generating declaration files... ${color.dim(`(${name})`)}`);
Expand Down Expand Up @@ -248,7 +248,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 +272,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
4 changes: 3 additions & 1 deletion packages/plugin-dts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export type PluginDtsOptions = {
banner?: string;
footer?: string;
redirect?: DtsRedirect;
tsgo?: boolean;
};

export type DtsEntry = {
Expand Down Expand Up @@ -93,14 +94,15 @@ 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.tsgo = options.tsgo ?? false;

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

api.onBeforeEnvironmentCompile(
async ({ isWatch, isFirstCompile, environment }) => {
if (!isFirstCompile) {
if (!isFirstCompile && !options.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