Skip to content

Commit a4963ca

Browse files
committed
Report buildInfo size during extendedDiagnostics
1 parent 48aebcd commit a4963ca

File tree

11 files changed

+323
-64
lines changed

11 files changed

+323
-64
lines changed

src/compiler/builder.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
returnFalse, returnUndefined, SemanticDiagnosticsBuilderProgram, Set, skipTypeChecking, some, SourceFile,
1616
sourceFileMayBeEmitted, SourceMapEmitResult, toPath, tryAddToSet, WriteFileCallback, WriteFileCallbackData,
1717
} from "./_namespaces/ts";
18+
import * as performance from "./_namespaces/ts.performance";
1819

1920
/** @internal */
2021
export interface ReusableDiagnostic extends ReusableDiagnosticRelatedInformation {
@@ -910,10 +911,18 @@ export function isProgramBundleEmitBuildInfo(info: ProgramBuildInfo): info is Pr
910911
return !!outFile(info.options || {});
911912
}
912913

914+
function getBuildInfo(state: BuilderProgramState, getCanonicalFileName: GetCanonicalFileName, bundle: BundleBuildInfo | undefined) {
915+
performance.mark("beforeGetProgramBuildInfo");
916+
const result = getBuildInfoWorker(state, getCanonicalFileName, bundle);
917+
performance.mark("afterGetProgramBuildInfo");
918+
performance.measure("BuildInfo generation", "beforeGetProgramBuildInfo", "afterGetProgramBuildInfo");
919+
return result;
920+
}
921+
913922
/**
914923
* Gets the program information to be emitted in buildInfo so that we can use it to create new program
915924
*/
916-
function getBuildInfo(state: BuilderProgramState, getCanonicalFileName: GetCanonicalFileName, bundle: BundleBuildInfo | undefined): BuildInfo {
925+
function getBuildInfoWorker(state: BuilderProgramState, getCanonicalFileName: GetCanonicalFileName, bundle: BundleBuildInfo | undefined): BuildInfo {
917926
const currentDirectory = Debug.checkDefined(state.program).getCurrentDirectory();
918927
const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getTsBuildInfoEmitOutputFilePath(state.compilerOptions)!, currentDirectory));
919928
// Convert the file name to Path here if we set the fileName instead to optimize multiple d.ts file emits and having to compute Canonical path

src/compiler/emitter.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,13 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
448448
return;
449449
}
450450
const buildInfo = host.getBuildInfo(bundle) || createBuildInfo(/*program*/ undefined, bundle);
451+
performance.mark("beforeBuildInfoStringify");
452+
const buildInfoText = getBuildInfoText(buildInfo);
453+
performance.mark("afterBuildInfoStringify");
454+
performance.measure("BuildInfo stringify", "beforeBuildInfoStringify", "afterBuildInfoStringify");
455+
host.buildInfoCallbacks?.onWrite(buildInfoText.length);
451456
// Pass buildinfo as additional data to avoid having to reparse
452-
writeFile(host, emitterDiagnostics, buildInfoPath, getBuildInfoText(buildInfo), /*writeByteOrderMark*/ false, /*sourceFiles*/ undefined, { buildInfo });
457+
writeFile(host, emitterDiagnostics, buildInfoPath, buildInfoText, /*writeByteOrderMark*/ false, /*sourceFiles*/ undefined, { buildInfo });
453458
}
454459

455460
function emitJsFileOrBundle(
@@ -849,7 +854,7 @@ function emitUsingBuildInfoWorker(
849854
const createHash = maybeBind(host, host.createHash);
850855
const { buildInfoPath, jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath } = getOutputPathsForBundle(config.options, /*forceDtsPaths*/ false);
851856
// If host directly provides buildinfo we can get it directly. This allows host to cache the buildinfo
852-
const buildInfo = host.getBuildInfo!(buildInfoPath!, config.options.configFilePath);
857+
const buildInfo = host.getBuildInfo!(buildInfoPath!, config.options);
853858
if (!buildInfo) return buildInfoPath!;
854859
if (!buildInfo.bundle || !buildInfo.bundle.js || (declarationFilePath && !buildInfo.bundle.dts)) return buildInfoPath!;
855860

@@ -951,6 +956,7 @@ function emitUsingBuildInfoWorker(
951956
redirectTargetsMap: createMultiMap(),
952957
getFileIncludeReasons: notImplemented,
953958
createHash,
959+
buildInfoCallbacks: host.buildInfoCallbacks,
954960
};
955961
emitFiles(
956962
notImplementedResolver,

src/compiler/factory/nodeFactory.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6913,11 +6913,14 @@ export function createInputFilesWithFilePaths(
69136913
const getAndCacheBuildInfo = () => {
69146914
if (buildInfo === undefined && buildInfoPath) {
69156915
if (host?.getBuildInfo) {
6916-
buildInfo = host.getBuildInfo(buildInfoPath, options!.configFilePath) ?? false;
6916+
buildInfo = host.getBuildInfo(buildInfoPath, options!) ?? false;
69176917
}
69186918
else {
6919+
host?.buildInfoCallbacks?.onReadStart(options);
69196920
const result = textGetter(buildInfoPath);
6921+
host?.buildInfoCallbacks?.onReadText(result);
69206922
buildInfo = result !== undefined ? getBuildInfo(buildInfoPath, result) ?? false : false;
6923+
host?.buildInfoCallbacks?.onReadEnd();
69216924
}
69226925
}
69236926
return buildInfo || undefined;

src/compiler/program.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2147,6 +2147,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
21472147
redirectTargetsMap,
21482148
getFileIncludeReasons: program.getFileIncludeReasons,
21492149
createHash: maybeBind(host, host.createHash),
2150+
buildInfoCallbacks: host.buildInfoCallbacks,
21502151
};
21512152
}
21522153

src/compiler/tsbuildPublic.ts

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

139139
// TODO: To do better with watch mode and normal build mode api that creates program and emits files
140140
// This currently helps enable --diagnostics and --extendedDiagnostics
141-
afterProgramEmitAndDiagnostics?(program: T): void;
142-
/** @internal */ beforeEmitBundle?(config: ParsedCommandLine): void;
143-
/** @internal */ afterEmitBundle?(config: ParsedCommandLine): void;
141+
afterProgramEmitAndDiagnostics?(program: T, host?: CompilerHost): void;
142+
/** @internal */ beforeEmitBundle?(config: ParsedCommandLine, host: CompilerHost): void;
143+
/** @internal */ afterEmitBundle?(config: ParsedCommandLine, host: CompilerHost): void;
144144

145145
// For testing
146146
/** @internal */ now?(): Date;
@@ -350,7 +350,7 @@ function createSolutionBuilderState<T extends BuilderProgram>(watch: boolean, ho
350350
compilerHost.resolveTypeReferenceDirectives = (typeReferenceDirectiveNames, containingFile, redirectedReference, _options, containingFileMode) =>
351351
loadWithTypeDirectiveCache<ResolvedTypeReferenceDirective>(Debug.checkEachDefined(typeReferenceDirectiveNames), containingFile, redirectedReference, containingFileMode, loader);
352352
}
353-
compilerHost.getBuildInfo = (fileName, configFilePath) => getBuildInfo(state, fileName, toResolvedConfigFilePath(state, configFilePath as ResolvedConfigFileName), /*modifiedTime*/ undefined);
353+
compilerHost.getBuildInfo = (fileName, options) => getBuildInfo(state, fileName, options, toResolvedConfigFilePath(state, options.configFilePath as ResolvedConfigFileName), /*modifiedTime*/ undefined);
354354

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

@@ -1011,6 +1011,8 @@ function createBuildOrUpdateInvalidedProject<T extends BuilderProgram>(
10111011
// Don't emit .d.ts if there are decl file errors
10121012
if (declDiagnostics) {
10131013
program.restoreEmitState(saved);
1014+
// Revert buildInfo write size
1015+
state.compilerHost.buildInfoCallbacks?.revertLastWrite();
10141016
({ buildResult, step } = buildErrors(
10151017
state,
10161018
projectPath,
@@ -1028,6 +1030,7 @@ function createBuildOrUpdateInvalidedProject<T extends BuilderProgram>(
10281030

10291031
// Actual Emit
10301032
const { host, compilerHost } = state;
1033+
compilerHost.buildInfoCallbacks?.clearLastWrite();
10311034
const resultFlags = program.hasChangedEmitSignature?.() ? BuildResultFlags.None : BuildResultFlags.DeclarationOutputUnchanged;
10321035
const emitterDiagnostics = createDiagnosticCollection();
10331036
const emittedOutputs = new Map<Path, string>();
@@ -1130,7 +1133,7 @@ function createBuildOrUpdateInvalidedProject<T extends BuilderProgram>(
11301133
// Update js, and source map
11311134
const { compilerHost } = state;
11321135
state.projectCompilerOptions = config.options;
1133-
state.host.beforeEmitBundle?.(config);
1136+
state.host.beforeEmitBundle?.(config, compilerHost);
11341137
const outputFiles = emitUsingBuildInfo(
11351138
config,
11361139
compilerHost,
@@ -1411,12 +1414,12 @@ function afterProgramDone<T extends BuilderProgram>(
14111414
if (program) {
14121415
if (state.write) listFiles(program, state.write);
14131416
if (state.host.afterProgramEmitAndDiagnostics) {
1414-
state.host.afterProgramEmitAndDiagnostics(program);
1417+
state.host.afterProgramEmitAndDiagnostics(program, state.compilerHost);
14151418
}
14161419
program.releaseProgram();
14171420
}
14181421
else if (state.host.afterEmitBundle) {
1419-
state.host.afterEmitBundle(config);
1422+
state.host.afterEmitBundle(config, state.compilerHost);
14201423
}
14211424
state.projectCompilerOptions = state.baseCompilerOptions;
14221425
}
@@ -1539,14 +1542,18 @@ function getBuildInfoCacheEntry(state: SolutionBuilderState, buildInfoPath: stri
15391542
return existing?.path === path ? existing : undefined;
15401543
}
15411544

1542-
function getBuildInfo(state: SolutionBuilderState, buildInfoPath: string, resolvedConfigPath: ResolvedConfigFilePath, modifiedTime: Date | undefined): BuildInfo | undefined {
1545+
function getBuildInfo(state: SolutionBuilderState, buildInfoPath: string, options: CompilerOptions, resolvedConfigPath: ResolvedConfigFilePath, modifiedTime: Date | undefined): BuildInfo | undefined {
15431546
const path = toPath(state, buildInfoPath);
15441547
const existing = state.buildInfoCache.get(resolvedConfigPath);
15451548
if (existing !== undefined && existing.path === path) {
15461549
return existing.buildInfo || undefined;
15471550
}
1551+
const host = (modifiedTime ? state.host : state.compilerHost);
1552+
host.buildInfoCallbacks?.onReadStart(options);
15481553
const value = state.readFileWithCache(buildInfoPath);
1554+
host.buildInfoCallbacks?.onReadText(value);
15491555
const buildInfo = value ? ts.getBuildInfo(buildInfoPath, value) : undefined;
1556+
host.buildInfoCallbacks?.onReadEnd();
15501557
state.buildInfoCache.set(resolvedConfigPath, { path, buildInfo: buildInfo || false, modifiedTime: modifiedTime || missingFileModifiedTime });
15511558
return buildInfo;
15521559
}
@@ -1636,7 +1643,7 @@ function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCom
16361643
};
16371644
}
16381645

1639-
const buildInfo = getBuildInfo(state, buildInfoPath, resolvedPath, buildInfoTime);
1646+
const buildInfo = getBuildInfo(state, buildInfoPath, project.options, resolvedPath, buildInfoTime);
16401647
if (!buildInfo) {
16411648
// Error reading buildInfo
16421649
return {

src/compiler/types.ts

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

7294+
/** @internal */
7295+
export interface BuildInfoCallbacks {
7296+
onReadStart(compilerOptions: CompilerOptions | undefined): void;
7297+
onReadText(text: string | undefined): void;
7298+
onReadEnd(): void;
7299+
onWrite(size: number): void;
7300+
revertLastWrite(): void;
7301+
clearLastWrite(): void;
7302+
}
7303+
72947304
export interface ResolutionInfo<T> {
72957305
names: readonly T[];
72967306
reusedNames: readonly T[] | undefined;
@@ -7344,7 +7354,8 @@ export interface CompilerHost extends ModuleResolutionHost {
73447354
// For testing:
73457355
/** @internal */ disableUseFileVersionAsSignature?: boolean;
73467356
/** @internal */ storeFilesChangingSignatureDuringEmit?: boolean;
7347-
/** @internal */ getBuildInfo?(fileName: string, configFilePath: string | undefined): BuildInfo | undefined;
7357+
/** @internal */ getBuildInfo?(fileName: string, options: CompilerOptions): BuildInfo | undefined;
7358+
/** @internal */ buildInfoCallbacks?: BuildInfoCallbacks;
73487359
}
73497360

73507361
/** true if --out otherwise source file name *
@@ -7650,6 +7661,7 @@ export interface EmitHost extends ScriptReferenceHost, ModuleSpecifierResolution
76507661
getSourceFileFromReference: Program["getSourceFileFromReference"];
76517662
readonly redirectTargetsMap: RedirectTargetsMap;
76527663
createHash?(data: string): string;
7664+
buildInfoCallbacks: BuildInfoCallbacks | undefined;
76537665
}
76547666

76557667
/** @internal */

src/compiler/watch.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ export function createCompilerHostFromProgramHost(host: ProgramHost<any>, getCom
680680
readDirectory: maybeBind(host, host.readDirectory),
681681
disableUseFileVersionAsSignature: host.disableUseFileVersionAsSignature,
682682
storeFilesChangingSignatureDuringEmit: host.storeFilesChangingSignatureDuringEmit,
683+
buildInfoCallbacks: host.buildInfoCallbacks,
683684
};
684685
}
685686

src/compiler/watchPublic.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as ts from "./_namespaces/ts";
22
import {
3-
BuilderProgram, BuildInfo, canJsonReportNoInputFiles, changeCompilerHostLikeToUseCache,
3+
BuilderProgram, BuildInfo, BuildInfoCallbacks, canJsonReportNoInputFiles, changeCompilerHostLikeToUseCache,
44
changesAffectModuleResolution, cleanExtendedConfigCache, clearMap, clearSharedExtendedConfigFileWatcher,
55
closeFileWatcher, closeFileWatcherOf, CompilerHost, CompilerOptions, ConfigFileDiagnosticsReporter,
66
ConfigFileProgramReloadLevel, createBuilderProgramUsingProgramBuildInfo, createCachedDirectoryStructureHost,
@@ -28,20 +28,23 @@ export interface ReadBuildProgramHost {
2828
getCurrentDirectory(): string;
2929
readFile(fileName: string): string | undefined;
3030
/** @internal */
31-
getBuildInfo?(fileName: string, configFilePath: string | undefined): BuildInfo | undefined;
31+
getBuildInfo?(fileName: string, options: CompilerOptions): BuildInfo | undefined;
32+
/** @internal */ buildInfoCallbacks?: BuildInfoCallbacks;
3233
}
3334
export function readBuilderProgram(compilerOptions: CompilerOptions, host: ReadBuildProgramHost) {
3435
const buildInfoPath = getTsBuildInfoEmitOutputFilePath(compilerOptions);
3536
if (!buildInfoPath) return undefined;
3637
let buildInfo;
3738
if (host.getBuildInfo) {
3839
// host provides buildinfo, get it from there. This allows host to cache it
39-
buildInfo = host.getBuildInfo(buildInfoPath, compilerOptions.configFilePath);
40+
buildInfo = host.getBuildInfo(buildInfoPath, compilerOptions);
4041
}
4142
else {
43+
host.buildInfoCallbacks?.onReadStart(compilerOptions);
4244
const content = host.readFile(buildInfoPath);
43-
if (!content) return undefined;
44-
buildInfo = getBuildInfo(buildInfoPath, content);
45+
host.buildInfoCallbacks?.onReadText(content);
46+
buildInfo = content ? getBuildInfo(buildInfoPath, content) : undefined;
47+
host.buildInfoCallbacks?.onReadEnd();
4548
}
4649
if (!buildInfo || buildInfo.version !== version || !buildInfo.program) return undefined;
4750
return createBuilderProgramUsingProgramBuildInfo(buildInfo, buildInfoPath, host);
@@ -152,6 +155,7 @@ export interface ProgramHost<T extends BuilderProgram> {
152155
// TODO: GH#18217 Optional methods are frequently asserted
153156
createDirectory?(path: string): void;
154157
writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void;
158+
buildInfoCallbacks?: BuildInfoCallbacks;
155159
// For testing
156160
disableUseFileVersionAsSignature?: boolean;
157161
storeFilesChangingSignatureDuringEmit?: boolean;
@@ -166,7 +170,7 @@ export interface WatchCompilerHost<T extends BuilderProgram> extends ProgramHost
166170
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
167171

168172
/** If provided, callback to invoke after every new program creation */
169-
afterProgramCreate?(program: T): void;
173+
afterProgramCreate?(program: T, host?: CompilerHost): void;
170174
}
171175

172176
/**
@@ -502,7 +506,7 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
502506

503507
reportFileChangeDetectedOnCreateProgram = false;
504508
if (host.afterProgramCreate && program !== builderProgram) {
505-
host.afterProgramCreate(builderProgram);
509+
host.afterProgramCreate(builderProgram, compilerHost);
506510
}
507511

508512
compilerHost.readFile = originalReadFile;

0 commit comments

Comments
 (0)