Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: unecessary program updates by removing timeout methods #1693

Merged
merged 10 commits into from Mar 12, 2020
41 changes: 23 additions & 18 deletions packages/typescript-estree/src/create-program/createWatchProgram.ts
Expand Up @@ -250,7 +250,7 @@ function createWatchProgram(
filePath === currentLintOperationState.filePath
? currentLintOperationState.code
: oldReadFile(filePath, encoding);
if (fileContent) {
if (fileContent !== undefined) {
parsedFilesSeenHash.set(filePath, createHash(fileContent));
}
return fileContent;
Expand Down Expand Up @@ -309,25 +309,30 @@ function createWatchProgram(
);
oldOnDirectoryStructureHostCreate(host);
};

/*
* The watch change callbacks TS provides us all have a 250ms delay before firing
* https://github.com/microsoft/TypeScript/blob/b845800bdfcc81c8c72e2ac6fdc2c1df0cdab6f9/src/compiler/watch.ts#L1013
*
* We live in a synchronous world, so we can't wait for that.
* This is a bit of a hack, but it lets us immediately force updates when we detect a tsconfig or directory change
*/
const oldSetTimeout = watchCompilerHost.setTimeout;
watchCompilerHost.setTimeout = (cb, ms, ...args): unknown => {
if (ms === 250) {
cb();
return null;
watchCompilerHost.trace = log;

// Since we don't want to asynchronously update program we want to disable timeout methods
// So any changes in the program will be delayed and updated when getProgram is called on watch
// But because of https://github.com/microsoft/TypeScript/pull/37308 we cannot just set it to undefined
// instead save it and call before getProgram is called
let callback: (() => void) | undefined;
sheetalkamat marked this conversation as resolved.
Show resolved Hide resolved
watchCompilerHost.setTimeout = (cb, _ms, ...args): unknown => {
callback = cb.bind(/*this*/ undefined, ...args);
return callback;
};
watchCompilerHost.clearTimeout = (): void => {
callback = undefined;
};
const watch = ts.createWatchProgram(watchCompilerHost);
const originalGetProgram = watch.getProgram;
watch.getProgram = (): ts.SemanticDiagnosticsBuilderProgram => {
if (callback) {
callback();
}

return oldSetTimeout?.(cb, ms, ...args);
callback = undefined;
return originalGetProgram.call(watch);
};

return ts.createWatchProgram(watchCompilerHost);
return watch;
}

function hasTSConfigChanged(tsconfigPath: CanonicalPath): boolean {
Expand Down