Skip to content

Commit a0b44b3

Browse files
committed
perf: cleanup context for non-eager build
1 parent 7a22741 commit a0b44b3

File tree

6 files changed

+117
-88
lines changed

6 files changed

+117
-88
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ dist
44
*.log
55
.DS_Store
66
.eslintcache
7+
*.tgz
78

89
temp

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"typecheck": "tsc --noEmit",
3939
"format": "prettier --cache --write .",
4040
"release": "bumpp && pnpm publish",
41+
"prepack": "pnpm run build",
4142
"prepublishOnly": "pnpm run build"
4243
},
4344
"peerDependencies": {

src/generate.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
RE_VUE,
1717
} from './filename.ts'
1818
import type { OptionsResolved } from './options.ts'
19-
import type { TscOptions, TscResult } from './tsc/index.ts'
19+
import type { TscContext, TscOptions, TscResult } from './tsc/index.ts'
2020
import type { TscFunctions } from './tsc/worker.ts'
2121
import type { Plugin, SourceMapInput } from 'rolldown'
2222

@@ -80,7 +80,8 @@ export function createGeneratePlugin({
8080

8181
let childProcess: ChildProcess | undefined
8282
let rpc: BirpcReturn<TscFunctions> | undefined
83-
let tscEmit: (options: TscOptions) => TscResult
83+
let tscModule: typeof import('./tsc/index.ts')
84+
let tscContext: TscContext | undefined
8485
let tsgoDist: string | undefined
8586

8687
if (!tsgo && parallel) {
@@ -123,7 +124,8 @@ export function createGeneratePlugin({
123124
{ stdio: 'inherit' },
124125
)
125126
} else if (!parallel && (!isolatedDeclarations || vue)) {
126-
;({ tscEmit } = await import('./tsc/index.ts'))
127+
tscModule = await import('./tsc/index.ts')
128+
tscContext = eager ? undefined : tscModule.createContext()
127129
}
128130

129131
if (!Array.isArray(options.input)) {
@@ -257,12 +259,13 @@ export function createGeneratePlugin({
257259
entries,
258260
id,
259261
vue,
262+
context: tscContext,
260263
}
261264
let result: TscResult
262265
if (parallel) {
263266
result = await rpc!.tscEmit(options)
264267
} else {
265-
result = tscEmit(options)
268+
result = tscModule.tscEmit(options)
266269
}
267270
if (result.error) {
268271
return this.error(result.error)
@@ -297,8 +300,8 @@ export function createGeneratePlugin({
297300
childProcess?.kill()
298301
if (tsgoDist) {
299302
await rm(tsgoDist, { recursive: true, force: true }).catch(() => {})
300-
tsgoDist = undefined
301303
}
304+
tscContext = tsgoDist = undefined
302305
},
303306
}
304307
}

src/tsc/index.ts

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,42 @@
11
import path from 'node:path'
22
import Debug from 'debug'
33
import ts from 'typescript'
4-
import { fsSystem, memorySystem } from './system.ts'
4+
import { createFsSystem, createMemorySystem } from './system.ts'
55
import { createVueProgramFactory } from './vue.ts'
66
import type { TsConfigJson } from 'get-tsconfig'
77
import type { SourceMapInput } from 'rolldown'
88

9+
export interface TscContext {
10+
programs: ts.Program[]
11+
files: Map<string, string>
12+
}
13+
14+
export interface TscModule {
15+
program: ts.Program
16+
file: ts.SourceFile
17+
}
18+
19+
export interface TscOptions {
20+
tsconfig?: string
21+
tsconfigRaw: TsConfigJson
22+
cwd: string
23+
incremental: boolean
24+
entries?: string[]
25+
id: string
26+
vue?: boolean
27+
context?: TscContext
28+
}
29+
930
const debug = Debug('rolldown-plugin-dts:tsc')
1031
debug(`loaded typescript: ${ts.version}`)
1132

12-
const programs: ts.Program[] = []
33+
export function createContext(): TscContext {
34+
const programs: ts.Program[] = []
35+
const files = new Map<string, string>()
36+
return { programs, files }
37+
}
38+
39+
const globalContext: TscContext = createContext()
1340

1441
const formatHost: ts.FormatDiagnosticsHost = {
1542
getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
@@ -32,24 +59,9 @@ const defaultCompilerOptions: ts.CompilerOptions = {
3259
moduleResolution: ts.ModuleResolutionKind.Bundler,
3360
}
3461

35-
export interface TscModule {
36-
program: ts.Program
37-
file: ts.SourceFile
38-
}
39-
40-
export interface TscOptions {
41-
tsconfig?: string
42-
tsconfigRaw: TsConfigJson
43-
cwd: string
44-
incremental: boolean
45-
entries?: string[]
46-
id: string
47-
vue?: boolean
48-
}
49-
5062
function createOrGetTsModule(options: TscOptions): TscModule {
51-
const { id, entries } = options
52-
const program = programs.find((program) => {
63+
const { id, entries, context = globalContext } = options
64+
const program = context.programs.find((program) => {
5365
const roots = program.getRootFileNames()
5466
if (entries) {
5567
return entries.every((entry) => roots.includes(entry))
@@ -67,7 +79,7 @@ function createOrGetTsModule(options: TscOptions): TscModule {
6779
const module = createTsProgram(options)
6880
debug(`created program for module: ${id}`)
6981

70-
programs.push(module.program)
82+
context.programs.push(module.program)
7183
return module
7284
}
7385

@@ -80,9 +92,15 @@ function createOrGetTsModule(options: TscOptions): TscModule {
8092
* changes) the build will be super fast. If `incremental` is `false`, the
8193
* `.tsbuildinfo` file will only be written to the memory.
8294
*/
83-
function buildSolution(tsconfig: string, incremental: boolean) {
95+
function buildSolution(
96+
tsconfig: string,
97+
incremental: boolean,
98+
context: TscContext,
99+
) {
84100
debug(`building projects for ${tsconfig} with incremental: ${incremental}`)
85-
const system = incremental ? fsSystem : memorySystem
101+
const system = (incremental ? createFsSystem : createMemorySystem)(
102+
context.files,
103+
)
86104

87105
const host = ts.createSolutionBuilderHost(system)
88106
const builder = ts.createSolutionBuilder(host, [tsconfig], {
@@ -105,7 +123,9 @@ function createTsProgram({
105123
incremental,
106124
vue,
107125
cwd,
126+
context = globalContext,
108127
}: TscOptions): TscModule {
128+
const fsSystem = createFsSystem(context.files)
109129
const parsedCmd = ts.parseJsonConfigFileContent(
110130
tsconfigRaw,
111131
fsSystem,
@@ -114,7 +134,7 @@ function createTsProgram({
114134

115135
// If the tsconfig has project references, build the project tree.
116136
if (tsconfig && parsedCmd.projectReferences?.length) {
117-
buildSolution(tsconfig, incremental)
137+
buildSolution(tsconfig, incremental, context)
118138
}
119139

120140
const compilerOptions: ts.CompilerOptions = {

src/tsc/system.ts

Lines changed: 58 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,71 +3,75 @@ import ts from 'typescript'
33

44
const debug = Debug('rolldown-plugin-dts:tsc-system')
55

6-
const files: Map<string, string> = new Map()
6+
/**
7+
* A system that writes files to both memory and disk. It will try read files
8+
* from memory firstly and fallback to disk if not found.
9+
*/
10+
export function createFsSystem(files: Map<string, string>): ts.System {
11+
return {
12+
...ts.sys,
713

8-
// A system that writes files to both memory and disk. It will try read files
9-
// from memory firstly and fallback to disk if not found.ƒ
10-
export const fsSystem: ts.System = {
11-
...ts.sys,
14+
// Hide the output of tsc by default
15+
write(message: string): void {
16+
debug(message)
17+
},
1218

13-
// Hide the output of tsc by default
14-
write(message: string): void {
15-
debug(message)
16-
},
19+
// Copied from
20+
// https://github.com/microsoft/TypeScript-Website/blob/b0e9a5c0/packages/typescript-vfs/src/index.ts#L571-L574
21+
resolvePath(path) {
22+
if (files.has(path)) {
23+
return path
24+
}
25+
return ts.sys.resolvePath(path)
26+
},
1727

18-
// Copied from
19-
// https://github.com/microsoft/TypeScript-Website/blob/b0e9a5c0/packages/typescript-vfs/src/index.ts#L571C5-L574C7
20-
resolvePath(path) {
21-
if (files.has(path)) {
22-
return path
23-
}
24-
return ts.sys.resolvePath(path)
25-
},
28+
// Copied from
29+
// https://github.com/microsoft/TypeScript-Website/blob/b0e9a5c0/packages/typescript-vfs/src/index.ts#L532C1-L534C8
30+
directoryExists(directory) {
31+
if (Array.from(files.keys()).some((path) => path.startsWith(directory))) {
32+
return true
33+
}
34+
return ts.sys.directoryExists(directory)
35+
},
2636

27-
// Copied from
28-
// https://github.com/microsoft/TypeScript-Website/blob/b0e9a5c0/packages/typescript-vfs/src/index.ts#L532C1-L534C8
29-
directoryExists(directory) {
30-
if (Array.from(files.keys()).some((path) => path.startsWith(directory))) {
31-
return true
32-
}
33-
return ts.sys.directoryExists(directory)
34-
},
37+
fileExists(fileName) {
38+
if (files.has(fileName)) {
39+
return true
40+
}
41+
return ts.sys.fileExists(fileName)
42+
},
3543

36-
fileExists(fileName) {
37-
if (files.has(fileName)) {
38-
return true
39-
}
40-
return ts.sys.fileExists(fileName)
41-
},
44+
readFile(fileName, ...args) {
45+
if (files.has(fileName)) {
46+
return files.get(fileName)
47+
}
48+
return ts.sys.readFile(fileName, ...args)
49+
},
4250

43-
readFile(fileName, ...args) {
44-
if (files.has(fileName)) {
45-
return files.get(fileName)
46-
}
47-
return ts.sys.readFile(fileName, ...args)
48-
},
51+
writeFile(path, data, ...args) {
52+
files.set(path, data)
53+
ts.sys.writeFile(path, data, ...args)
54+
},
4955

50-
writeFile(path, data, ...args) {
51-
files.set(path, data)
52-
ts.sys.writeFile(path, data, ...args)
53-
},
54-
55-
deleteFile(fileName, ...args) {
56-
files.delete(fileName)
57-
ts.sys.deleteFile?.(fileName, ...args)
58-
},
56+
deleteFile(fileName, ...args) {
57+
files.delete(fileName)
58+
ts.sys.deleteFile?.(fileName, ...args)
59+
},
60+
}
5961
}
6062

6163
// A system that only writes files to memory. It will read files from both
6264
// memory and disk.
63-
export const memorySystem: ts.System = {
64-
...fsSystem,
65+
export function createMemorySystem(files: Map<string, string>): ts.System {
66+
return {
67+
...createFsSystem(files),
6568

66-
writeFile(path, data) {
67-
files.set(path, data)
68-
},
69+
writeFile(path, data) {
70+
files.set(path, data)
71+
},
6972

70-
deleteFile(fileName) {
71-
files.delete(fileName)
72-
},
73+
deleteFile(fileName) {
74+
files.delete(fileName)
75+
},
76+
}
7377
}

tests/tsc.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ describe('tsc', () => {
9999
cwd: tempDir,
100100
absolute: false,
101101
})
102-
expect(tsBuildInfoFiles).toMatchInlineSnapshot(`
103-
[
104-
"dir1/tsconfig.1.tsbuildinfo",
105-
"dir2/tsconfig.2.tsbuildinfo",
106-
]
107-
`)
102+
expect(tsBuildInfoFiles.sort()).toMatchInlineSnapshot(`
103+
[
104+
"dir1/tsconfig.1.tsbuildinfo",
105+
"dir2/tsconfig.2.tsbuildinfo",
106+
]
107+
`)
108108
})
109109

110110
test('vue-sfc w/ ts-compiler', async () => {

0 commit comments

Comments
 (0)