fix(language-service): [Ivy] create compiler only when program changes (#39231)

This commit fixes a bug in which a new Ivy Compiler is created every time
language service receives a new request. This is not needed if the
`ts.Program` has not changed.

A new class `CompilerFactory` is created to manage Compiler lifecycle and
keep track of template changes so that it knows when to override them.
With this change, we no longer need the method `getModifiedResourceFile()`
on the adapter. Instead, we call `overrideComponentTemplate` on the
template type checker.

This commit also changes the incremental build strategy from
`PatchedIncrementalBuildStrategy` to `TrackedIncrementalBuildStrategy`.

PR Close #39231
This commit is contained in:
Keen Yee Liau
2020-10-09 16:46:55 -07:00
committed by atscott
parent a83693ddd9
commit 8f1317f06f
7 changed files with 275 additions and 91 deletions

View File

@ -19,7 +19,6 @@ export class LanguageServiceAdapter implements NgCompilerAdapter {
readonly unifiedModulesHost = null; // only used in Bazel
readonly rootDirs: AbsoluteFsPath[];
private readonly templateVersion = new Map<string, string>();
private readonly modifiedTemplates = new Set<string>();
constructor(private readonly project: ts.server.Project) {
this.rootDirs = project.getCompilationSettings().rootDirs?.map(absoluteFrom) || [];
@ -68,37 +67,13 @@ export class LanguageServiceAdapter implements NgCompilerAdapter {
}
const version = this.project.getScriptVersion(fileName);
this.templateVersion.set(fileName, version);
this.modifiedTemplates.delete(fileName);
return snapshot.getText(0, snapshot.getLength());
}
/**
* getModifiedResourceFiles() is an Angular-specific method for notifying
* the Angular compiler templates that have changed since it last read them.
* It is a method on ExtendedTsCompilerHost, see
* packages/compiler-cli/src/ngtsc/core/api/src/interfaces.ts
*/
getModifiedResourceFiles(): Set<string> {
return this.modifiedTemplates;
}
/**
* Check whether the specified `fileName` is newer than the last time it was
* read. If it is newer, register it and return true, otherwise do nothing and
* return false.
* @param fileName path to external template
*/
registerTemplateUpdate(fileName: string): boolean {
if (!isExternalTemplate(fileName)) {
return false;
}
isTemplateDirty(fileName: string): boolean {
const lastVersion = this.templateVersion.get(fileName);
const latestVersion = this.project.getScriptVersion(fileName);
if (lastVersion !== latestVersion) {
this.modifiedTemplates.add(fileName);
return true;
}
return false;
return lastVersion !== latestVersion;
}
}