angular-cn/packages/language-service/ivy/compiler_factory.ts
Alex Rickabaugh 94ec0af582 refactor(compiler-cli): replace the IncrementalDriver with a new design (#41475)
This commit replaces the `IncrementalDriver` abstraction which powered
incremental compilation in the compiler with a new `IncrementalCompilation`
design. Principally, it separates two concerns which were tied together in
the previous implementation:

1. Tracking the reusable state of a compilation at any given point that
   could be reused in a subsequent future compilation.

2. Making use of a prior compilation's state to accelerate the current one.

The new abstraction adds explicit tracking and types to deal with both of
these concerns separately, which greatly reduces the complexity of the state
tracking that `IncrementalDriver` used to perform.

PR Close #41475
2021-04-13 13:05:35 -07:00

71 lines
3.0 KiB
TypeScript

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {CompilationTicket, freshCompilationTicket, incrementalFromCompilerTicket, NgCompiler, resourceChangeTicket} from '@angular/compiler-cli/src/ngtsc/core';
import {NgCompilerOptions} from '@angular/compiler-cli/src/ngtsc/core/api';
import {AbsoluteFsPath, resolve} from '@angular/compiler-cli/src/ngtsc/file_system';
import {TrackedIncrementalBuildStrategy} from '@angular/compiler-cli/src/ngtsc/incremental';
import {ProgramDriver} from '@angular/compiler-cli/src/ngtsc/program_driver';
import {LanguageServiceAdapter} from './adapters';
/**
* Manages the `NgCompiler` instance which backs the language service, updating or replacing it as
* needed to produce an up-to-date understanding of the current program.
*
* TODO(alxhub): currently the options used for the compiler are specified at `CompilerFactory`
* construction, and are not changable. In a real project, users can update `tsconfig.json`. We need
* to properly handle a change in the compiler options, either by having an API to update the
* `CompilerFactory` to use new options, or by replacing it entirely.
*/
export class CompilerFactory {
private readonly incrementalStrategy = new TrackedIncrementalBuildStrategy();
private compiler: NgCompiler|null = null;
constructor(
private readonly adapter: LanguageServiceAdapter,
private readonly programStrategy: ProgramDriver,
private readonly options: NgCompilerOptions,
) {}
getOrCreate(): NgCompiler {
const program = this.programStrategy.getProgram();
const modifiedResourceFiles = new Set<AbsoluteFsPath>();
for (const fileName of this.adapter.getModifiedResourceFiles() ?? []) {
modifiedResourceFiles.add(resolve(fileName));
}
if (this.compiler !== null && program === this.compiler.getCurrentProgram()) {
if (modifiedResourceFiles.size > 0) {
// Only resource files have changed since the last NgCompiler was created.
const ticket = resourceChangeTicket(this.compiler, modifiedResourceFiles);
this.compiler = NgCompiler.fromTicket(ticket, this.adapter);
} else {
// The previous NgCompiler is being reused, but we still want to reset its performance
// tracker to capture only the operations that are needed to service the current request.
this.compiler.perfRecorder.reset();
}
return this.compiler;
}
let ticket: CompilationTicket;
if (this.compiler === null) {
ticket = freshCompilationTicket(
program, this.options, this.incrementalStrategy, this.programStrategy,
/* perfRecorder */ null, true, true);
} else {
ticket = incrementalFromCompilerTicket(
this.compiler, program, this.incrementalStrategy, this.programStrategy,
modifiedResourceFiles, /* perfRecorder */ null);
}
this.compiler = NgCompiler.fromTicket(ticket, this.adapter);
return this.compiler;
}
}