Skip to content

Commit 88f23b9

Browse files
committed
Report buildInfo size during extendedDiagnostics
1 parent 59e659a commit 88f23b9

File tree

11 files changed

+314
-52
lines changed

11 files changed

+314
-52
lines changed

src/compiler/builder.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ import {
8181
WriteFileCallback,
8282
WriteFileCallbackData,
8383
} from "./_namespaces/ts";
84+
import * as performance from "./_namespaces/ts.performance";
8485

8586
/** @internal */
8687
export interface ReusableDiagnostic extends ReusableDiagnosticRelatedInformation {
@@ -957,10 +958,18 @@ export function isProgramBundleEmitBuildInfo(info: ProgramBuildInfo): info is Pr
957958
return !!outFile(info.options || {});
958959
}
959960

961+
function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | undefined) {
962+
performance.mark("beforeGetProgramBuildInfo");
963+
const result = getBuildInfoWorker(state, bundle);
964+
performance.mark("afterGetProgramBuildInfo");
965+
performance.measure("BuildInfo generation", "beforeGetProgramBuildInfo", "afterGetProgramBuildInfo");
966+
return result;
967+
}
968+
960969
/**
961970
* Gets the program information to be emitted in buildInfo so that we can use it to create new program
962971
*/
963-
function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | undefined): BuildInfo {
972+
function getBuildInfoWorker(state: BuilderProgramState, bundle: BundleBuildInfo | undefined): BuildInfo {
964973
const currentDirectory = Debug.checkDefined(state.program).getCurrentDirectory();
965974
const getCanonicalFileName = createGetCanonicalFileName(state.program!.useCaseSensitiveFileNames());
966975
const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getTsBuildInfoEmitOutputFilePath(state.compilerOptions)!, currentDirectory));

src/compiler/emitter.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -812,8 +812,13 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
812812
return;
813813
}
814814
const buildInfo = host.getBuildInfo(bundle) || createBuildInfo(/*program*/ undefined, bundle);
815+
performance.mark("beforeBuildInfoStringify");
816+
const buildInfoText = getBuildInfoText(buildInfo);
817+
performance.mark("afterBuildInfoStringify");
818+
performance.measure("BuildInfo stringify", "beforeBuildInfoStringify", "afterBuildInfoStringify");
819+
host.buildInfoCallbacks?.onWrite(buildInfoText.length);
815820
// Pass buildinfo as additional data to avoid having to reparse
816-
writeFile(host, emitterDiagnostics, buildInfoPath, getBuildInfoText(buildInfo), /*writeByteOrderMark*/ false, /*sourceFiles*/ undefined, { buildInfo });
821+
writeFile(host, emitterDiagnostics, buildInfoPath, buildInfoText, /*writeByteOrderMark*/ false, /*sourceFiles*/ undefined, { buildInfo });
817822
}
818823

819824
function emitJsFileOrBundle(
@@ -1212,7 +1217,7 @@ function emitUsingBuildInfoWorker(
12121217
): EmitUsingBuildInfoResult {
12131218
const { buildInfoPath, jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath } = getOutputPathsForBundle(config.options, /*forceDtsPaths*/ false);
12141219
// If host directly provides buildinfo we can get it directly. This allows host to cache the buildinfo
1215-
const buildInfo = host.getBuildInfo!(buildInfoPath!, config.options.configFilePath);
1220+
const buildInfo = host.getBuildInfo!(buildInfoPath!, config.options);
12161221
if (!buildInfo) return buildInfoPath!;
12171222
if (!buildInfo.bundle || !buildInfo.bundle.js || (declarationFilePath && !buildInfo.bundle.dts)) return buildInfoPath!;
12181223

@@ -1314,6 +1319,7 @@ function emitUsingBuildInfoWorker(
13141319
redirectTargetsMap: createMultiMap(),
13151320
getFileIncludeReasons: notImplemented,
13161321
createHash: maybeBind(host, host.createHash),
1322+
buildInfoCallbacks: host.buildInfoCallbacks,
13171323
};
13181324
emitFiles(
13191325
notImplementedResolver,

src/compiler/factory/nodeFactory.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7301,11 +7301,14 @@ export function createInputFilesWithFilePaths(
73017301
const getAndCacheBuildInfo = () => {
73027302
if (buildInfo === undefined && buildInfoPath) {
73037303
if (host?.getBuildInfo) {
7304-
buildInfo = host.getBuildInfo(buildInfoPath, options!.configFilePath) ?? false;
7304+
buildInfo = host.getBuildInfo(buildInfoPath, options!) ?? false;
73057305
}
73067306
else {
7307+
host?.buildInfoCallbacks?.onReadStart(options);
73077308
const result = textGetter(buildInfoPath);
7309+
host?.buildInfoCallbacks?.onReadText(result);
73087310
buildInfo = result !== undefined ? getBuildInfo(buildInfoPath, result) ?? false : false;
7311+
host?.buildInfoCallbacks?.onReadEnd();
73097312
}
73107313
}
73117314
return buildInfo || undefined;

src/compiler/program.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2401,6 +2401,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
24012401
redirectTargetsMap,
24022402
getFileIncludeReasons: program.getFileIncludeReasons,
24032403
createHash: maybeBind(host, host.createHash),
2404+
buildInfoCallbacks: host.buildInfoCallbacks,
24042405
};
24052406
}
24062407

src/compiler/tsbuildPublic.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,9 @@ export interface SolutionBuilderHostBase<T extends BuilderProgram> extends Progr
243243

244244
// TODO: To do better with watch mode and normal build mode api that creates program and emits files
245245
// This currently helps enable --diagnostics and --extendedDiagnostics
246-
afterProgramEmitAndDiagnostics?(program: T): void;
247-
/** @internal */ beforeEmitBundle?(config: ParsedCommandLine): void;
248-
/** @internal */ afterEmitBundle?(config: ParsedCommandLine): void;
246+
afterProgramEmitAndDiagnostics?(program: T, host?: CompilerHost): void;
247+
/** @internal */ beforeEmitBundle?(config: ParsedCommandLine, host: CompilerHost): void;
248+
/** @internal */ afterEmitBundle?(config: ParsedCommandLine, host: CompilerHost): void;
249249

250250
// For testing
251251
/** @internal */ now?(): Date;
@@ -455,7 +455,7 @@ function createSolutionBuilderState<T extends BuilderProgram>(watch: boolean, ho
455455
compilerHost.resolveTypeReferenceDirectives = (typeReferenceDirectiveNames, containingFile, redirectedReference, _options, containingFileMode) =>
456456
loadWithTypeDirectiveCache<ResolvedTypeReferenceDirective>(Debug.checkEachDefined(typeReferenceDirectiveNames), containingFile, redirectedReference, containingFileMode, loader);
457457
}
458-
compilerHost.getBuildInfo = (fileName, configFilePath) => getBuildInfo(state, fileName, toResolvedConfigFilePath(state, configFilePath as ResolvedConfigFileName), /*modifiedTime*/ undefined);
458+
compilerHost.getBuildInfo = (fileName, options) => getBuildInfo(state, fileName, options, toResolvedConfigFilePath(state, options.configFilePath as ResolvedConfigFileName), /*modifiedTime*/ undefined);
459459

460460
const { watchFile, watchDirectory, writeLog } = createWatchFactory<ResolvedConfigFileName>(hostWithWatch, options);
461461

@@ -1116,6 +1116,8 @@ function createBuildOrUpdateInvalidedProject<T extends BuilderProgram>(
11161116
// Don't emit .d.ts if there are decl file errors
11171117
if (declDiagnostics) {
11181118
program.restoreEmitState(saved);
1119+
// Revert buildInfo write size
1120+
state.compilerHost.buildInfoCallbacks?.revertLastWrite();
11191121
({ buildResult, step } = buildErrors(
11201122
state,
11211123
projectPath,
@@ -1133,6 +1135,7 @@ function createBuildOrUpdateInvalidedProject<T extends BuilderProgram>(
11331135

11341136
// Actual Emit
11351137
const { host, compilerHost } = state;
1138+
compilerHost.buildInfoCallbacks?.clearLastWrite();
11361139
const resultFlags = program.hasChangedEmitSignature?.() ? BuildResultFlags.None : BuildResultFlags.DeclarationOutputUnchanged;
11371140
const emitterDiagnostics = createDiagnosticCollection();
11381141
const emittedOutputs = new Map<Path, string>();
@@ -1235,7 +1238,7 @@ function createBuildOrUpdateInvalidedProject<T extends BuilderProgram>(
12351238
// Update js, and source map
12361239
const { compilerHost } = state;
12371240
state.projectCompilerOptions = config.options;
1238-
state.host.beforeEmitBundle?.(config);
1241+
state.host.beforeEmitBundle?.(config, compilerHost);
12391242
const outputFiles = emitUsingBuildInfo(
12401243
config,
12411244
compilerHost,
@@ -1516,12 +1519,12 @@ function afterProgramDone<T extends BuilderProgram>(
15161519
if (program) {
15171520
if (state.write) listFiles(program, state.write);
15181521
if (state.host.afterProgramEmitAndDiagnostics) {
1519-
state.host.afterProgramEmitAndDiagnostics(program);
1522+
state.host.afterProgramEmitAndDiagnostics(program, state.compilerHost);
15201523
}
15211524
program.releaseProgram();
15221525
}
15231526
else if (state.host.afterEmitBundle) {
1524-
state.host.afterEmitBundle(config);
1527+
state.host.afterEmitBundle(config, state.compilerHost);
15251528
}
15261529
state.projectCompilerOptions = state.baseCompilerOptions;
15271530
}
@@ -1644,14 +1647,18 @@ function getBuildInfoCacheEntry(state: SolutionBuilderState, buildInfoPath: stri
16441647
return existing?.path === path ? existing : undefined;
16451648
}
16461649

1647-
function getBuildInfo(state: SolutionBuilderState, buildInfoPath: string, resolvedConfigPath: ResolvedConfigFilePath, modifiedTime: Date | undefined): BuildInfo | undefined {
1650+
function getBuildInfo(state: SolutionBuilderState, buildInfoPath: string, options: CompilerOptions, resolvedConfigPath: ResolvedConfigFilePath, modifiedTime: Date | undefined): BuildInfo | undefined {
16481651
const path = toPath(state, buildInfoPath);
16491652
const existing = state.buildInfoCache.get(resolvedConfigPath);
16501653
if (existing !== undefined && existing.path === path) {
16511654
return existing.buildInfo || undefined;
16521655
}
1656+
const host = (modifiedTime ? state.host : state.compilerHost);
1657+
host.buildInfoCallbacks?.onReadStart(options);
16531658
const value = state.readFileWithCache(buildInfoPath);
1659+
host.buildInfoCallbacks?.onReadText(value);
16541660
const buildInfo = value ? ts.getBuildInfo(buildInfoPath, value) : undefined;
1661+
host.buildInfoCallbacks?.onReadEnd();
16551662
state.buildInfoCache.set(resolvedConfigPath, { path, buildInfo: buildInfo || false, modifiedTime: modifiedTime || missingFileModifiedTime });
16561663
return buildInfo;
16571664
}
@@ -1741,7 +1748,7 @@ function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCom
17411748
};
17421749
}
17431750

1744-
const buildInfo = getBuildInfo(state, buildInfoPath, resolvedPath, buildInfoTime);
1751+
const buildInfo = getBuildInfo(state, buildInfoPath, project.options, resolvedPath, buildInfoTime);
17451752
if (!buildInfo) {
17461753
// Error reading buildInfo
17471754
return {

src/compiler/types.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7309,6 +7309,16 @@ export type HasInvalidatedResolutions = (sourceFile: Path) => boolean;
73097309
/** @internal */
73107310
export type HasChangedAutomaticTypeDirectiveNames = () => boolean;
73117311

7312+
/** @internal */
7313+
export interface BuildInfoCallbacks {
7314+
onReadStart(compilerOptions: CompilerOptions | undefined): void;
7315+
onReadText(text: string | undefined): void;
7316+
onReadEnd(): void;
7317+
onWrite(size: number): void;
7318+
revertLastWrite(): void;
7319+
clearLastWrite(): void;
7320+
}
7321+
73127322
export interface ResolutionInfo<T> {
73137323
names: readonly T[];
73147324
reusedNames: readonly T[] | undefined;
@@ -7362,7 +7372,8 @@ export interface CompilerHost extends ModuleResolutionHost {
73627372
// For testing:
73637373
/** @internal */ disableUseFileVersionAsSignature?: boolean;
73647374
/** @internal */ storeFilesChangingSignatureDuringEmit?: boolean;
7365-
/** @internal */ getBuildInfo?(fileName: string, configFilePath: string | undefined): BuildInfo | undefined;
7375+
/** @internal */ getBuildInfo?(fileName: string, options: CompilerOptions): BuildInfo | undefined;
7376+
/** @internal */ buildInfoCallbacks?: BuildInfoCallbacks;
73667377
}
73677378

73687379
/** true if --out otherwise source file name *
@@ -7669,6 +7680,7 @@ export interface EmitHost extends ScriptReferenceHost, ModuleSpecifierResolution
76697680
getSourceFileFromReference: Program["getSourceFileFromReference"];
76707681
readonly redirectTargetsMap: RedirectTargetsMap;
76717682
createHash?(data: string): string;
7683+
buildInfoCallbacks: BuildInfoCallbacks | undefined;
76727684
}
76737685

76747686
/** @internal */

src/compiler/watch.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,7 @@ export function createCompilerHostFromProgramHost(host: ProgramHost<any>, getCom
767767
readDirectory: maybeBind(host, host.readDirectory),
768768
disableUseFileVersionAsSignature: host.disableUseFileVersionAsSignature,
769769
storeFilesChangingSignatureDuringEmit: host.storeFilesChangingSignatureDuringEmit,
770+
buildInfoCallbacks: host.buildInfoCallbacks,
770771
};
771772
}
772773

src/compiler/watchPublic.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as ts from "./_namespaces/ts";
22
import {
33
BuilderProgram,
44
BuildInfo,
5+
BuildInfoCallbacks,
56
canJsonReportNoInputFiles,
67
changeCompilerHostLikeToUseCache,
78
changesAffectModuleResolution,
@@ -97,20 +98,23 @@ export interface ReadBuildProgramHost {
9798
getCurrentDirectory(): string;
9899
readFile(fileName: string): string | undefined;
99100
/** @internal */
100-
getBuildInfo?(fileName: string, configFilePath: string | undefined): BuildInfo | undefined;
101+
getBuildInfo?(fileName: string, options: CompilerOptions): BuildInfo | undefined;
102+
/** @internal */ buildInfoCallbacks?: BuildInfoCallbacks;
101103
}
102104
export function readBuilderProgram(compilerOptions: CompilerOptions, host: ReadBuildProgramHost) {
103105
const buildInfoPath = getTsBuildInfoEmitOutputFilePath(compilerOptions);
104106
if (!buildInfoPath) return undefined;
105107
let buildInfo;
106108
if (host.getBuildInfo) {
107109
// host provides buildinfo, get it from there. This allows host to cache it
108-
buildInfo = host.getBuildInfo(buildInfoPath, compilerOptions.configFilePath);
110+
buildInfo = host.getBuildInfo(buildInfoPath, compilerOptions);
109111
}
110112
else {
113+
host.buildInfoCallbacks?.onReadStart(compilerOptions);
111114
const content = host.readFile(buildInfoPath);
112-
if (!content) return undefined;
113-
buildInfo = getBuildInfo(buildInfoPath, content);
115+
host.buildInfoCallbacks?.onReadText(content);
116+
buildInfo = content ? getBuildInfo(buildInfoPath, content) : undefined;
117+
host.buildInfoCallbacks?.onReadEnd();
114118
}
115119
if (!buildInfo || buildInfo.version !== version || !buildInfo.program) return undefined;
116120
return createBuilderProgramUsingProgramBuildInfo(buildInfo, buildInfoPath, host);
@@ -221,6 +225,7 @@ export interface ProgramHost<T extends BuilderProgram> {
221225
// TODO: GH#18217 Optional methods are frequently asserted
222226
createDirectory?(path: string): void;
223227
writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void;
228+
buildInfoCallbacks?: BuildInfoCallbacks;
224229
// For testing
225230
disableUseFileVersionAsSignature?: boolean;
226231
storeFilesChangingSignatureDuringEmit?: boolean;
@@ -235,7 +240,7 @@ export interface WatchCompilerHost<T extends BuilderProgram> extends ProgramHost
235240
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
236241

237242
/** If provided, callback to invoke after every new program creation */
238-
afterProgramCreate?(program: T): void;
243+
afterProgramCreate?(program: T, host?: CompilerHost): void;
239244
}
240245

241246
/**
@@ -571,7 +576,7 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
571576

572577
reportFileChangeDetectedOnCreateProgram = false;
573578
if (host.afterProgramCreate && program !== builderProgram) {
574-
host.afterProgramCreate(builderProgram);
579+
host.afterProgramCreate(builderProgram, compilerHost);
575580
}
576581

577582
compilerHost.readFile = originalReadFile;

0 commit comments

Comments
 (0)