refactor(compiler-cli): introduce CompilationTicket system for NgCompiler (#40561)
Previously, the incremental flow for NgCompiler was simple: when creating a new NgCompiler instance, the consumer could pass state from a previous compilation, which would cause the new compilation to be performed incrementally. "Local" information about TypeScript files which had not changed would be passed from the old compilation to the new and reused, while "global" information would always be recalculated. However, this flow could be made more efficient in certain cases, such as when no TypeScript files are changed in a new compilation. In this case, _all_ information extracted during the first compilation is reusable. Doing this involves reusing the previous `NgCompiler` instance (the container for such global information) and updating it, instead of creating a new one for the next compilation. This approach works cleanly, but complicates the lifecycle of `NgCompiler`. To prevent consumers from having to deal with the mechanics of reuse vs incremental steps of `NgCompiler`, a new `CompilationTicket` mechanism is added in this commit. Consumers obtain a `CompilationTicket` via one of several code paths depending on the nature of the incoming compilation, and use the `CompilationTicket` to obtain an `NgCompiler` instance. This instance may be a fresh compilation, a new `NgCompiler` for an incremental compilation, or an existing `NgCompiler` that's been updated to optimally process a resource-only change. Consumers can use the new `NgCompiler` without knowledge of its provenance. PR Close #40561
This commit is contained in:
parent
a8c5c8ed2d
commit
21e24d1474
|
@ -22,11 +22,22 @@ A compiler which integrates Angular compilation into this process follows a very
|
|||
1. A `ts.CompilerHost` is created.
|
||||
2. That `ts.CompilerHost` is wrapped in an `NgCompilerHost`, which adds Angular specific files to the compilation.
|
||||
3. A `ts.Program` is created from the `NgCompilerHost` and its augmented set of root files.
|
||||
4. An `NgCompiler` is created using the `ts.Program`.
|
||||
4. A `CompilationTicket` is created, optionally incorporating any state from a previous compilation run.
|
||||
4. An `NgCompiler` is created using the `CompilationTicket`.
|
||||
5. Diagnostics can be gathered from the `ts.Program` as normal, as well as from the `NgCompiler`.
|
||||
6. Prior to `emit`, `NgCompiler.prepareEmit` is called to retrieve the Angular transformers which need to be fed to `ts.Program.emit`.
|
||||
7. `emit` is called on the `ts.Program` with the Angular transformers from above, which produces JavaScript code with Angular extensions.
|
||||
|
||||
# `NgCompiler` and incremental compilation
|
||||
|
||||
The Angular compiler is capable of incremental compilation, where information from a previous compilation is used to accelerate the next compilation. During compilation, the compiler produces two major kinds of information: local information (such as component and directive metadata) and global information (such as reified NgModule scopes). Incremental compilation is managed in two ways:
|
||||
|
||||
1. For most changes, a new `NgCompiler` can selectively inherit local information from a previous instance, and only needs to recompute it where an underlying TypeScript file has change. Global information is always recomputed from scratch in this case.
|
||||
|
||||
2. For specific changes, such as those in component resources, an `NgCompiler` can be reused in its entirety, and updated to incorporate the effects of such changes without needing to recompute any other information.
|
||||
|
||||
Note that these two modes differ in terms of whether a new `NgCompiler` instance is needed or whether a previous one can reused. To prevent leaking this implementation complexity and shield consumers from having to manage the lifecycle of `NgCompiler` so specifically, this process is abstracted via `CompilationTicket`s. Consumers first obtain a `CompilationTicket` (depending on the nature of the incoming change), and then use this ticket to retrieve an `NgCompiler` instance. In creating the `CompilationTicket`, the compiler can decide whether to reuse an old `NgCompiler` instance or to create a new one.
|
||||
|
||||
## Asynchronous compilation
|
||||
|
||||
In some compilation environments (such as the Webpack-driven compilation inside the Angular CLI), various inputs to the compilation are only producible in an asynchronous fashion. For example, SASS compilation of `styleUrls` that link to SASS files requires spawning a child Webpack compilation. To support this, Angular has an asynchronous interface for loading such resources.
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export {NgCompiler} from './src/compiler';
|
||||
export {NgCompilerHost} from './src/host';
|
||||
export * from './src/compiler';
|
||||
export {NgCompilerHost} from './src/host';
|
|
@ -55,6 +55,132 @@ interface LazyCompilationState {
|
|||
resourceRegistry: ResourceRegistry;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Discriminant type for a `CompilationTicket`.
|
||||
*/
|
||||
export enum CompilationTicketKind {
|
||||
Fresh,
|
||||
IncrementalTypeScript,
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin an Angular compilation operation from scratch.
|
||||
*/
|
||||
export interface FreshCompilationTicket {
|
||||
kind: CompilationTicketKind.Fresh;
|
||||
options: NgCompilerOptions;
|
||||
incrementalBuildStrategy: IncrementalBuildStrategy;
|
||||
typeCheckingProgramStrategy: TypeCheckingProgramStrategy;
|
||||
enableTemplateTypeChecker: boolean;
|
||||
usePoisonedData: boolean;
|
||||
tsProgram: ts.Program;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin an Angular compilation operation that incorporates changes to TypeScript code.
|
||||
*/
|
||||
export interface IncrementalTypeScriptCompilationTicket {
|
||||
kind: CompilationTicketKind.IncrementalTypeScript;
|
||||
options: NgCompilerOptions;
|
||||
oldProgram: ts.Program;
|
||||
newProgram: ts.Program;
|
||||
incrementalBuildStrategy: IncrementalBuildStrategy;
|
||||
typeCheckingProgramStrategy: TypeCheckingProgramStrategy;
|
||||
newDriver: IncrementalDriver;
|
||||
enableTemplateTypeChecker: boolean;
|
||||
usePoisonedData: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* A request to begin Angular compilation, either starting from scratch or from a known prior state.
|
||||
*
|
||||
* `CompilationTicket`s are used to initialize (or update) an `NgCompiler` instance, the core of the
|
||||
* Angular compiler. They abstract the starting state of compilation and allow `NgCompiler` to be
|
||||
* managed independently of any incremental compilation lifecycle.
|
||||
*/
|
||||
export type CompilationTicket = FreshCompilationTicket|IncrementalTypeScriptCompilationTicket;
|
||||
|
||||
/**
|
||||
* Create a `CompilationTicket` for a brand new compilation, using no prior state.
|
||||
*/
|
||||
export function freshCompilationTicket(
|
||||
tsProgram: ts.Program, options: NgCompilerOptions,
|
||||
incrementalBuildStrategy: IncrementalBuildStrategy,
|
||||
typeCheckingProgramStrategy: TypeCheckingProgramStrategy, enableTemplateTypeChecker: boolean,
|
||||
usePoisonedData: boolean): CompilationTicket {
|
||||
return {
|
||||
kind: CompilationTicketKind.Fresh,
|
||||
tsProgram,
|
||||
options,
|
||||
incrementalBuildStrategy,
|
||||
typeCheckingProgramStrategy,
|
||||
enableTemplateTypeChecker,
|
||||
usePoisonedData,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a `CompilationTicket` as efficiently as possible, based on a previous `NgCompiler`
|
||||
* instance and a new `ts.Program`.
|
||||
*/
|
||||
export function incrementalFromCompilerTicket(
|
||||
oldCompiler: NgCompiler, newProgram: ts.Program,
|
||||
incrementalBuildStrategy: IncrementalBuildStrategy,
|
||||
typeCheckingProgramStrategy: TypeCheckingProgramStrategy,
|
||||
modifiedResourceFiles: Set<string>): CompilationTicket {
|
||||
const oldProgram = oldCompiler.getNextProgram();
|
||||
const oldDriver = oldCompiler.incrementalStrategy.getIncrementalDriver(oldProgram);
|
||||
if (oldDriver === null) {
|
||||
// No incremental step is possible here, since no IncrementalDriver was found for the old
|
||||
// program.
|
||||
return freshCompilationTicket(
|
||||
newProgram, oldCompiler.options, incrementalBuildStrategy, typeCheckingProgramStrategy,
|
||||
oldCompiler.enableTemplateTypeChecker, oldCompiler.usePoisonedData);
|
||||
}
|
||||
|
||||
const newDriver =
|
||||
IncrementalDriver.reconcile(oldProgram, oldDriver, newProgram, modifiedResourceFiles);
|
||||
|
||||
return {
|
||||
kind: CompilationTicketKind.IncrementalTypeScript,
|
||||
enableTemplateTypeChecker: oldCompiler.enableTemplateTypeChecker,
|
||||
usePoisonedData: oldCompiler.usePoisonedData,
|
||||
options: oldCompiler.options,
|
||||
incrementalBuildStrategy,
|
||||
typeCheckingProgramStrategy,
|
||||
newDriver,
|
||||
oldProgram,
|
||||
newProgram,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a `CompilationTicket` directly from an old `ts.Program` and associated Angular compilation
|
||||
* state, along with a new `ts.Program`.
|
||||
*/
|
||||
export function incrementalFromDriverTicket(
|
||||
oldProgram: ts.Program, oldDriver: IncrementalDriver, newProgram: ts.Program,
|
||||
options: NgCompilerOptions, incrementalBuildStrategy: IncrementalBuildStrategy,
|
||||
typeCheckingProgramStrategy: TypeCheckingProgramStrategy, modifiedResourceFiles: Set<string>,
|
||||
enableTemplateTypeChecker: boolean, usePoisonedData: boolean): CompilationTicket {
|
||||
const newDriver =
|
||||
IncrementalDriver.reconcile(oldProgram, oldDriver, newProgram, modifiedResourceFiles);
|
||||
return {
|
||||
kind: CompilationTicketKind.IncrementalTypeScript,
|
||||
oldProgram,
|
||||
newProgram,
|
||||
options,
|
||||
incrementalBuildStrategy,
|
||||
newDriver,
|
||||
typeCheckingProgramStrategy,
|
||||
enableTemplateTypeChecker,
|
||||
usePoisonedData,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The heart of the Angular Ivy compiler.
|
||||
*
|
||||
|
@ -96,19 +222,56 @@ export class NgCompiler {
|
|||
private moduleResolver: ModuleResolver;
|
||||
private resourceManager: AdapterResourceLoader;
|
||||
private cycleAnalyzer: CycleAnalyzer;
|
||||
readonly incrementalDriver: IncrementalDriver;
|
||||
readonly ignoreForDiagnostics: Set<ts.SourceFile>;
|
||||
readonly ignoreForEmit: Set<ts.SourceFile>;
|
||||
|
||||
constructor(
|
||||
/**
|
||||
* Convert a `CompilationTicket` into an `NgCompiler` instance for the requested compilation.
|
||||
*
|
||||
* Depending on the nature of the compilation request, the `NgCompiler` instance may be reused
|
||||
* from a previous compilation and updated with any changes, it may be a new instance which
|
||||
* incrementally reuses state from a previous compilation, or it may represent a fresh compilation
|
||||
* entirely.
|
||||
*/
|
||||
static fromTicket(
|
||||
ticket: CompilationTicket, adapter: NgCompilerAdapter, perfRecorder?: PerfRecorder) {
|
||||
switch (ticket.kind) {
|
||||
case CompilationTicketKind.Fresh:
|
||||
return new NgCompiler(
|
||||
adapter,
|
||||
ticket.options,
|
||||
ticket.tsProgram,
|
||||
ticket.typeCheckingProgramStrategy,
|
||||
ticket.incrementalBuildStrategy,
|
||||
IncrementalDriver.fresh(ticket.tsProgram),
|
||||
ticket.enableTemplateTypeChecker,
|
||||
ticket.usePoisonedData,
|
||||
perfRecorder,
|
||||
);
|
||||
case CompilationTicketKind.IncrementalTypeScript:
|
||||
return new NgCompiler(
|
||||
adapter,
|
||||
ticket.options,
|
||||
ticket.newProgram,
|
||||
ticket.typeCheckingProgramStrategy,
|
||||
ticket.incrementalBuildStrategy,
|
||||
ticket.newDriver,
|
||||
ticket.enableTemplateTypeChecker,
|
||||
ticket.usePoisonedData,
|
||||
perfRecorder,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private constructor(
|
||||
private adapter: NgCompilerAdapter,
|
||||
private options: NgCompilerOptions,
|
||||
readonly options: NgCompilerOptions,
|
||||
private tsProgram: ts.Program,
|
||||
private typeCheckingProgramStrategy: TypeCheckingProgramStrategy,
|
||||
private incrementalStrategy: IncrementalBuildStrategy,
|
||||
private enableTemplateTypeChecker: boolean,
|
||||
private usePoisonedData: boolean,
|
||||
oldProgram: ts.Program|null = null,
|
||||
readonly typeCheckingProgramStrategy: TypeCheckingProgramStrategy,
|
||||
readonly incrementalStrategy: IncrementalBuildStrategy,
|
||||
readonly incrementalDriver: IncrementalDriver,
|
||||
readonly enableTemplateTypeChecker: boolean,
|
||||
readonly usePoisonedData: boolean,
|
||||
private perfRecorder: PerfRecorder = NOOP_PERF_RECORDER,
|
||||
) {
|
||||
this.constructionDiagnostics.push(...this.adapter.constructionDiagnostics);
|
||||
|
@ -136,31 +299,10 @@ export class NgCompiler {
|
|||
new ModuleResolver(tsProgram, this.options, this.adapter, moduleResolutionCache);
|
||||
this.resourceManager = new AdapterResourceLoader(adapter, this.options);
|
||||
this.cycleAnalyzer = new CycleAnalyzer(new ImportGraph(this.moduleResolver));
|
||||
|
||||
let modifiedResourceFiles: Set<string>|null = null;
|
||||
if (this.adapter.getModifiedResourceFiles !== undefined) {
|
||||
modifiedResourceFiles = this.adapter.getModifiedResourceFiles() || null;
|
||||
}
|
||||
|
||||
if (oldProgram === null) {
|
||||
this.incrementalDriver = IncrementalDriver.fresh(tsProgram);
|
||||
} else {
|
||||
const oldDriver = this.incrementalStrategy.getIncrementalDriver(oldProgram);
|
||||
if (oldDriver !== null) {
|
||||
this.incrementalDriver =
|
||||
IncrementalDriver.reconcile(oldProgram, oldDriver, tsProgram, modifiedResourceFiles);
|
||||
} else {
|
||||
// A previous ts.Program was used to create the current one, but it wasn't from an
|
||||
// `NgCompiler`. That doesn't hurt anything, but the Angular analysis will have to start
|
||||
// from a fresh state.
|
||||
this.incrementalDriver = IncrementalDriver.fresh(tsProgram);
|
||||
}
|
||||
}
|
||||
this.incrementalStrategy.setIncrementalDriver(this.incrementalDriver, tsProgram);
|
||||
|
||||
this.ignoreForDiagnostics =
|
||||
new Set(tsProgram.getSourceFiles().filter(sf => this.adapter.isShim(sf)));
|
||||
|
||||
this.ignoreForEmit = this.adapter.ignoreForEmit;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,16 +10,26 @@ import * as ts from 'typescript';
|
|||
|
||||
import {absoluteFrom as _, FileSystem, getFileSystem, getSourceFileOrError, NgtscCompilerHost, setFileSystem} from '../../file_system';
|
||||
import {runInEachFileSystem} from '../../file_system/testing';
|
||||
import {NoopIncrementalBuildStrategy} from '../../incremental';
|
||||
import {IncrementalBuildStrategy, NoopIncrementalBuildStrategy} from '../../incremental';
|
||||
import {ClassDeclaration, isNamedClassDeclaration} from '../../reflection';
|
||||
import {ReusedProgramStrategy} from '../../typecheck';
|
||||
import {OptimizeFor} from '../../typecheck/api';
|
||||
import {OptimizeFor, TypeCheckingProgramStrategy} from '../../typecheck/api';
|
||||
|
||||
import {NgCompilerOptions} from '../api';
|
||||
|
||||
import {NgCompiler} from '../src/compiler';
|
||||
import {freshCompilationTicket, NgCompiler} from '../src/compiler';
|
||||
import {NgCompilerHost} from '../src/host';
|
||||
|
||||
function makeFreshCompiler(
|
||||
host: NgCompilerHost, options: NgCompilerOptions, program: ts.Program,
|
||||
programStrategy: TypeCheckingProgramStrategy, incrementalStrategy: IncrementalBuildStrategy,
|
||||
enableTemplateTypeChecker: boolean, usePoisonedData: boolean): NgCompiler {
|
||||
const ticket = freshCompilationTicket(
|
||||
program, options, incrementalStrategy, programStrategy, enableTemplateTypeChecker,
|
||||
usePoisonedData);
|
||||
return NgCompiler.fromTicket(ticket, host);
|
||||
}
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('NgCompiler', () => {
|
||||
let fs: FileSystem;
|
||||
|
@ -50,7 +60,7 @@ runInEachFileSystem(() => {
|
|||
const baseHost = new NgtscCompilerHost(getFileSystem(), options);
|
||||
const host = NgCompilerHost.wrap(baseHost, [COMPONENT], options, /* oldProgram */ null);
|
||||
const program = ts.createProgram({host, options, rootNames: host.inputFiles});
|
||||
const compiler = new NgCompiler(
|
||||
const compiler = makeFreshCompiler(
|
||||
host, options, program, new ReusedProgramStrategy(program, host, options, []),
|
||||
new NoopIncrementalBuildStrategy(), /** enableTemplateTypeChecker */ false,
|
||||
/* usePoisonedData */ false);
|
||||
|
@ -101,7 +111,7 @@ runInEachFileSystem(() => {
|
|||
const program = ts.createProgram({host, options, rootNames: host.inputFiles});
|
||||
const CmpA = getClass(getSourceFileOrError(program, cmpAFile), 'CmpA');
|
||||
const CmpC = getClass(getSourceFileOrError(program, cmpCFile), 'CmpC');
|
||||
const compiler = new NgCompiler(
|
||||
const compiler = makeFreshCompiler(
|
||||
host, options, program, new ReusedProgramStrategy(program, host, options, []),
|
||||
new NoopIncrementalBuildStrategy(), /** enableTemplateTypeChecker */ false,
|
||||
/* usePoisonedData */ false);
|
||||
|
@ -153,7 +163,7 @@ runInEachFileSystem(() => {
|
|||
const program = ts.createProgram({host, options, rootNames: host.inputFiles});
|
||||
const CmpA = getClass(getSourceFileOrError(program, cmpAFile), 'CmpA');
|
||||
const CmpC = getClass(getSourceFileOrError(program, cmpCFile), 'CmpC');
|
||||
const compiler = new NgCompiler(
|
||||
const compiler = makeFreshCompiler(
|
||||
host, options, program, new ReusedProgramStrategy(program, host, options, []),
|
||||
new NoopIncrementalBuildStrategy(), /** enableTemplateTypeChecker */ false,
|
||||
/* usePoisonedData */ false);
|
||||
|
@ -187,7 +197,7 @@ runInEachFileSystem(() => {
|
|||
const host = NgCompilerHost.wrap(baseHost, [cmpAFile], options, /* oldProgram */ null);
|
||||
const program = ts.createProgram({host, options, rootNames: host.inputFiles});
|
||||
const CmpA = getClass(getSourceFileOrError(program, cmpAFile), 'CmpA');
|
||||
const compiler = new NgCompiler(
|
||||
const compiler = makeFreshCompiler(
|
||||
host, options, program, new ReusedProgramStrategy(program, host, options, []),
|
||||
new NoopIncrementalBuildStrategy(), /** enableTemplateTypeChecker */ false,
|
||||
/* usePoisonedData */ false);
|
||||
|
@ -223,7 +233,7 @@ runInEachFileSystem(() => {
|
|||
const host = NgCompilerHost.wrap(baseHost, [cmpAFile], options, /* oldProgram */ null);
|
||||
const program = ts.createProgram({host, options, rootNames: host.inputFiles});
|
||||
const CmpA = getClass(getSourceFileOrError(program, cmpAFile), 'CmpA');
|
||||
const compiler = new NgCompiler(
|
||||
const compiler = makeFreshCompiler(
|
||||
host, options, program, new ReusedProgramStrategy(program, host, options, []),
|
||||
new NoopIncrementalBuildStrategy(), /** enableTemplateTypeChecker */ false,
|
||||
/* usePoisonedData */ false);
|
||||
|
@ -255,7 +265,7 @@ runInEachFileSystem(() => {
|
|||
const baseHost = new NgtscCompilerHost(getFileSystem(), options);
|
||||
const host = NgCompilerHost.wrap(baseHost, [COMPONENT], options, /* oldProgram */ null);
|
||||
const program = ts.createProgram({host, options, rootNames: host.inputFiles});
|
||||
const compiler = new NgCompiler(
|
||||
const compiler = makeFreshCompiler(
|
||||
host, options, program, new ReusedProgramStrategy(program, host, options, []),
|
||||
new NoopIncrementalBuildStrategy(), /** enableTemplateTypeChecker */ false,
|
||||
/* usePoisonedData */ false);
|
||||
|
|
|
@ -24,6 +24,12 @@ export interface IncrementalBuildStrategy {
|
|||
* future compilations.
|
||||
*/
|
||||
setIncrementalDriver(driver: IncrementalDriver, program: ts.Program): void;
|
||||
|
||||
/**
|
||||
* Convert this `IncrementalBuildStrategy` into a possibly new instance to be used in the next
|
||||
* incremental compilation (may be a no-op if the strategy is not stateful).
|
||||
*/
|
||||
toNextBuildStrategy(): IncrementalBuildStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,6 +42,10 @@ export class NoopIncrementalBuildStrategy implements IncrementalBuildStrategy {
|
|||
}
|
||||
|
||||
setIncrementalDriver(): void {}
|
||||
|
||||
toNextBuildStrategy(): IncrementalBuildStrategy {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,6 +88,10 @@ export class PatchedProgramIncrementalBuildStrategy implements IncrementalBuildS
|
|||
setIncrementalDriver(driver: IncrementalDriver, program: ts.Program): void {
|
||||
(program as any)[SYM_INCREMENTAL_DRIVER] = driver;
|
||||
}
|
||||
|
||||
toNextBuildStrategy(): IncrementalBuildStrategy {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,8 +12,9 @@ import * as ts from 'typescript';
|
|||
import * as api from '../transformers/api';
|
||||
import {verifySupportedTypeScriptVersion} from '../typescript_support';
|
||||
|
||||
import {NgCompiler, NgCompilerHost} from './core';
|
||||
import {CompilationTicket, freshCompilationTicket, incrementalFromCompilerTicket, NgCompiler, NgCompilerHost} from './core';
|
||||
import {NgCompilerOptions} from './core/api';
|
||||
import {absoluteFrom, AbsoluteFsPath} from './file_system';
|
||||
import {TrackedIncrementalBuildStrategy} from './incremental';
|
||||
import {IndexedComponent} from './indexer';
|
||||
import {NOOP_PERF_RECORDER, PerfRecorder, PerfTracker} from './perf';
|
||||
|
@ -97,12 +98,34 @@ export class NgtscProgram implements api.Program {
|
|||
this.incrementalStrategy = oldProgram !== undefined ?
|
||||
oldProgram.incrementalStrategy.toNextBuildStrategy() :
|
||||
new TrackedIncrementalBuildStrategy();
|
||||
const modifiedResourceFiles = new Set<AbsoluteFsPath>();
|
||||
if (this.host.getModifiedResourceFiles !== undefined) {
|
||||
const strings = this.host.getModifiedResourceFiles();
|
||||
if (strings !== undefined) {
|
||||
for (const fileString of strings) {
|
||||
modifiedResourceFiles.add(absoluteFrom(fileString));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ticket: CompilationTicket;
|
||||
if (oldProgram === undefined) {
|
||||
ticket = freshCompilationTicket(
|
||||
this.tsProgram, options, this.incrementalStrategy, reusedProgramStrategy,
|
||||
/* enableTemplateTypeChecker */ false, /* usePoisonedData */ false);
|
||||
} else {
|
||||
ticket = incrementalFromCompilerTicket(
|
||||
oldProgram.compiler,
|
||||
this.tsProgram,
|
||||
this.incrementalStrategy,
|
||||
reusedProgramStrategy,
|
||||
modifiedResourceFiles,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Create the NgCompiler which will drive the rest of the compilation.
|
||||
this.compiler = new NgCompiler(
|
||||
this.host, options, this.tsProgram, reusedProgramStrategy, this.incrementalStrategy,
|
||||
/** enableTemplateTypeChecker */ false, /* usePoisonedData */ false, reuseProgram,
|
||||
this.perfRecorder);
|
||||
this.compiler = NgCompiler.fromTicket(ticket, this.host, this.perfRecorder);
|
||||
}
|
||||
|
||||
getTsProgram(): ts.Program {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {NgCompiler, NgCompilerHost} from './core';
|
||||
import {CompilationTicket, freshCompilationTicket, incrementalFromDriverTicket, NgCompiler, NgCompilerHost} from './core';
|
||||
import {NgCompilerOptions, UnifiedModulesHost} from './core/api';
|
||||
import {NodeJSFileSystem, setFileSystem} from './file_system';
|
||||
import {PatchedProgramIncrementalBuildStrategy} from './incremental';
|
||||
|
@ -101,10 +101,29 @@ export class NgTscPlugin implements TscPlugin {
|
|||
untagAllTsFiles(program);
|
||||
const typeCheckStrategy = new ReusedProgramStrategy(
|
||||
program, this.host, this.options, this.host.shimExtensionPrefixes);
|
||||
this._compiler = new NgCompiler(
|
||||
this.host, this.options, program, typeCheckStrategy,
|
||||
new PatchedProgramIncrementalBuildStrategy(), /** enableTemplateTypeChecker */ false,
|
||||
/* usePoisonedData */ false, oldProgram, NOOP_PERF_RECORDER);
|
||||
const strategy = new PatchedProgramIncrementalBuildStrategy();
|
||||
const oldDriver = oldProgram !== undefined ? strategy.getIncrementalDriver(oldProgram) : null;
|
||||
let ticket: CompilationTicket;
|
||||
|
||||
let modifiedResourceFiles: Set<string>|undefined = undefined;
|
||||
if (this.host.getModifiedResourceFiles !== undefined) {
|
||||
modifiedResourceFiles = this.host.getModifiedResourceFiles();
|
||||
}
|
||||
if (modifiedResourceFiles === undefined) {
|
||||
modifiedResourceFiles = new Set<string>();
|
||||
}
|
||||
|
||||
if (oldProgram === undefined || oldDriver === null) {
|
||||
ticket = freshCompilationTicket(
|
||||
program, this.options, strategy, typeCheckStrategy,
|
||||
/* enableTemplateTypeChecker */ false, /* usePoisonedData */ false);
|
||||
} else {
|
||||
strategy.toNextBuildStrategy().getIncrementalDriver(oldProgram);
|
||||
ticket = incrementalFromDriverTicket(
|
||||
oldProgram, oldDriver, program, this.options, strategy, typeCheckStrategy,
|
||||
modifiedResourceFiles, false, false);
|
||||
}
|
||||
this._compiler = NgCompiler.fromTicket(ticket, this.host, NOOP_PERF_RECORDER);
|
||||
return {
|
||||
ignoreForDiagnostics: this._compiler.ignoreForDiagnostics,
|
||||
ignoreForEmit: this._compiler.ignoreForEmit,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgCompiler} from '@angular/compiler-cli/src/ngtsc/core';
|
||||
import {CompilationTicket, freshCompilationTicket, incrementalFromCompilerTicket, NgCompiler} from '@angular/compiler-cli/src/ngtsc/core';
|
||||
import {NgCompilerOptions} from '@angular/compiler-cli/src/ngtsc/core/api';
|
||||
import {TrackedIncrementalBuildStrategy} from '@angular/compiler-cli/src/ngtsc/incremental';
|
||||
import {TypeCheckingProgramStrategy} from '@angular/compiler-cli/src/ngtsc/typecheck/api';
|
||||
|
@ -38,17 +38,15 @@ export class CompilerFactory {
|
|||
getOrCreate(): NgCompiler {
|
||||
const program = this.programStrategy.getProgram();
|
||||
if (this.compiler === null || program !== this.lastKnownProgram) {
|
||||
this.compiler = new NgCompiler(
|
||||
this.adapter, // like compiler host
|
||||
this.options, // angular compiler options
|
||||
program,
|
||||
this.programStrategy,
|
||||
this.incrementalStrategy,
|
||||
true, // enableTemplateTypeChecker
|
||||
true, // usePoisonedData
|
||||
this.lastKnownProgram,
|
||||
undefined, // perfRecorder (use default)
|
||||
);
|
||||
let ticket: CompilationTicket;
|
||||
if (this.compiler === null || this.lastKnownProgram === null) {
|
||||
ticket = freshCompilationTicket(
|
||||
program, this.options, this.incrementalStrategy, this.programStrategy, true, true);
|
||||
} else {
|
||||
ticket = incrementalFromCompilerTicket(
|
||||
this.compiler, program, this.incrementalStrategy, this.programStrategy, new Set());
|
||||
}
|
||||
this.compiler = NgCompiler.fromTicket(ticket, this.adapter);
|
||||
this.lastKnownProgram = program;
|
||||
}
|
||||
return this.compiler;
|
||||
|
|
Loading…
Reference in New Issue