Skip to content

Commit 359c43e

Browse files
authored
feat: experimental tsgo (#43)
1 parent 1b605b0 commit 359c43e

File tree

5 files changed

+181
-6
lines changed

5 files changed

+181
-6
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ Enabling this option can speed up builds by caching previous results, which is h
7676

7777
**Default:** `true` if your `tsconfig` has [`incremental`](https://www.typescriptlang.org/tsconfig/#incremental) or [`tsBuildInfoFile`](https://www.typescriptlang.org/tsconfig/#tsBuildInfoFile) enabled.
7878

79-
> **Note:** This option is only used when [`isolatedDeclarations`](#isolateddeclarations-boolean--omitisolateddeclarationsoptions-sourcemap) is `false`.
79+
> [!NOTE]
80+
> This option is only used when [`isolatedDeclarations`](#isolateddeclarations-boolean--omitisolateddeclarationsoptions-sourcemap) is `false`.
8081
8182
### `compilerOptions?: TsConfigJson.CompilerOptions`
8283

@@ -115,6 +116,17 @@ If `true`, the plugin will prepare all files listed in `tsconfig.json` for `tsc`
115116

116117
This is especially useful when you have a single `tsconfig.json` for multiple projects in a monorepo.
117118

119+
### `tsgo?: boolean | string`
120+
121+
**[Experimental]** Enables DTS generation using [`tsgo`](https://github.com/microsoft/typescript-go).
122+
123+
- To use this option, ensure that `@typescript/native-preview` is installed as a dependency.
124+
- Set to `true` to enable `tsgo` for the current project.
125+
- If a string is provided, it should be the root path of your source files.
126+
127+
> [!WARNING]
128+
> This option is experimental and not yet recommended for production environments.
129+
118130
## Differences from `rollup-plugin-dts`
119131

120132
### Isolated Declarations

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,15 @@
4141
"prepublishOnly": "pnpm run build"
4242
},
4343
"peerDependencies": {
44+
"@typescript/native-preview": ">=7.0.0-dev.20250601.1",
4445
"rolldown": "^1.0.0-beta.9",
4546
"typescript": "^5.0.0",
4647
"vue-tsc": "~2.2.0"
4748
},
4849
"peerDependenciesMeta": {
50+
"@typescript/native-preview": {
51+
"optional": true
52+
},
4953
"typescript": {
5054
"optional": true
5155
},
@@ -70,6 +74,7 @@
7074
"@types/babel__generator": "^7.27.0",
7175
"@types/debug": "^4.1.12",
7276
"@types/node": "^22.15.29",
77+
"@typescript/native-preview": "7.0.0-dev.20250601.1",
7378
"@volar/typescript": "^2.4.14",
7479
"@vue/language-core": "^2.2.10",
7580
"bumpp": "^10.1.1",

pnpm-lock.yaml

Lines changed: 81 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/generate.ts

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { fork, type ChildProcess } from 'node:child_process'
1+
import { fork, spawn, type ChildProcess } from 'node:child_process'
2+
import { existsSync } from 'node:fs'
3+
import { mkdtemp, readFile, rm } from 'node:fs/promises'
4+
import { tmpdir } from 'node:os'
5+
import path from 'node:path'
26
import { createBirpc, type BirpcReturn } from 'birpc'
37
import Debug from 'debug'
48
import { isolatedDeclaration as oxcIsolatedDeclaration } from 'rolldown/experimental'
@@ -20,6 +24,13 @@ const debug = Debug('rolldown-plugin-dts:generate')
2024

2125
const WORKER_URL = import.meta.WORKER_URL || './utils/tsc-worker.ts'
2226

27+
const spawnAsync = (...args: Parameters<typeof spawn>) =>
28+
new Promise<void>((resolve, reject) => {
29+
const child = spawn(...args)
30+
child.on('close', () => resolve())
31+
child.on('error', (error) => reject(error))
32+
})
33+
2334
export interface TsModule {
2435
/** `.ts` source code */
2536
code: string
@@ -40,6 +51,7 @@ export function createGeneratePlugin({
4051
vue,
4152
parallel,
4253
eager,
54+
tsgo,
4355
}: Pick<
4456
OptionsResolved,
4557
| 'cwd'
@@ -51,6 +63,7 @@ export function createGeneratePlugin({
5163
| 'vue'
5264
| 'parallel'
5365
| 'eager'
66+
| 'tsgo'
5467
>): Plugin {
5568
const dtsMap: DtsMap = new Map<string, TsModule>()
5669

@@ -68,8 +81,9 @@ export function createGeneratePlugin({
6881
let childProcess: ChildProcess | undefined
6982
let rpc: BirpcReturn<TscFunctions> | undefined
7083
let tscEmit: (options: TscOptions) => TscResult
84+
let tsgoDist: string | undefined
7185

72-
if (parallel) {
86+
if (!tsgo && parallel) {
7387
childProcess = fork(new URL(WORKER_URL, import.meta.url), {
7488
stdio: 'inherit',
7589
})
@@ -86,7 +100,29 @@ export function createGeneratePlugin({
86100
name: 'rolldown-plugin-dts:generate',
87101

88102
async buildStart(options) {
89-
if (!parallel && (!isolatedDeclarations || vue)) {
103+
if (tsgo) {
104+
const tsgoPkg = import.meta.resolve(
105+
'@typescript/native-preview/package.json',
106+
)
107+
const { default: getExePath } = await import(
108+
new URL('./lib/getExePath.js', tsgoPkg).href
109+
)
110+
const tsgo = getExePath()
111+
tsgoDist = await mkdtemp(path.join(tmpdir(), 'rolldown-plugin-dts-'))
112+
await spawnAsync(
113+
tsgo,
114+
[
115+
'--noEmit',
116+
'false',
117+
'--declaration',
118+
'--emitDeclarationOnly',
119+
...(tsconfig ? ['-p', tsconfig] : []),
120+
'--outDir',
121+
tsgoDist,
122+
],
123+
{ stdio: 'inherit' },
124+
)
125+
} else if (!parallel && (!isolatedDeclarations || vue)) {
90126
;({ tscEmit } = await import('./utils/tsc.ts'))
91127
}
92128

@@ -176,7 +212,24 @@ export function createGeneratePlugin({
176212
let map: SourceMapInput | undefined
177213
debug('generate dts %s from %s', dtsId, id)
178214

179-
if (isolatedDeclarations && !RE_VUE.test(id)) {
215+
if (tsgo) {
216+
if (RE_VUE.test(id))
217+
throw new Error('tsgo does not support Vue files.')
218+
const dtsPath = path.resolve(
219+
tsgoDist!,
220+
path.relative(
221+
path.resolve(typeof tsgo === 'string' ? tsgo : 'src'),
222+
filename_ts_to_dts(id),
223+
),
224+
)
225+
if (existsSync(dtsPath)) {
226+
dtsCode = await readFile(dtsPath, 'utf8')
227+
} else {
228+
throw new Error(
229+
`tsgo did not generate dts file for ${id}, please check your tsconfig.`,
230+
)
231+
}
232+
} else if (isolatedDeclarations && !RE_VUE.test(id)) {
180233
const result = oxcIsolatedDeclaration(id, code, isolatedDeclarations)
181234
if (result.errors.length) {
182235
const [error] = result.errors
@@ -240,8 +293,12 @@ export function createGeneratePlugin({
240293
}
241294
: undefined,
242295

243-
buildEnd() {
296+
async buildEnd() {
244297
childProcess?.kill()
298+
if (tsgoDist) {
299+
await rm(tsgoDist, { recursive: true, force: true }).catch(() => {})
300+
tsgoDist = undefined
301+
}
245302
},
246303
}
247304
}

src/options.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,15 @@ export interface Options {
120120
* This is especially useful when you have a single `tsconfig.json` for multiple projects in a monorepo.
121121
*/
122122
eager?: boolean
123+
124+
/**
125+
* **[Experimental]** Enables DTS generation using `tsgo`.
126+
*
127+
* To use this option, make sure `@typescript/native-preview` is installed as a dependency.
128+
*
129+
* **Note:** This option is not yet recommended for production environments.
130+
*/
131+
tsgo?: boolean | string
123132
}
124133

125134
type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U
@@ -133,6 +142,8 @@ export type OptionsResolved = Overwrite<
133142
}
134143
>
135144

145+
let warnedTsgo = false
146+
136147
export function resolveOptions({
137148
cwd = process.cwd(),
138149
tsconfig,
@@ -147,6 +158,7 @@ export function resolveOptions({
147158
vue = false,
148159
parallel = false,
149160
eager = false,
161+
tsgo = false,
150162
}: Options): OptionsResolved {
151163
let resolvedTsconfig: TsConfigJsonResolved | undefined
152164
if (tsconfig === true || tsconfig == null) {
@@ -188,6 +200,13 @@ export function resolveOptions({
188200
isolatedDeclarations.sourcemap = !!compilerOptions.declarationMap
189201
}
190202

203+
if (tsgo && !warnedTsgo) {
204+
console.warn(
205+
'The `tsgo` option is experimental and may change in the future.',
206+
)
207+
warnedTsgo = true
208+
}
209+
191210
return {
192211
cwd,
193212
tsconfig,
@@ -201,5 +220,6 @@ export function resolveOptions({
201220
vue,
202221
parallel,
203222
eager,
223+
tsgo,
204224
}
205225
}

0 commit comments

Comments
 (0)