perf(ivy): basic incremental compilation for ngtsc (#29380)

This commit introduces a mechanism for incremental compilation to the ngtsc
compiler.

Previously, incremental information was used in the construction of the
ts.Program for subsequent compilations, but was not used in ngtsc itself.

This commit adds an IncrementalState class, which tracks state between ngtsc
compilations. Currently, this supports skipping the TypeScript emit step
when the compiler can prove the contents of emit have not changed.

This is implemented for @Injectables as well as for files which don't
contain any Angular decorated types. These are the only files which can be
proven to be safe today.

See ngtsc/incremental/README.md for more details.

PR Close #29380
This commit is contained in:
Alex Rickabaugh
2019-03-18 12:25:26 -07:00
committed by Jason Aden
parent 7316212c1e
commit 7041e61562
11 changed files with 241 additions and 4 deletions

View File

@ -18,6 +18,7 @@ import {CycleAnalyzer, ImportGraph} from './cycles';
import {ErrorCode, ngErrorCode} from './diagnostics';
import {FlatIndexGenerator, ReferenceGraph, checkForPrivateExports, findFlatIndexEntryPoint} from './entry_point';
import {AbsoluteModuleStrategy, AliasGenerator, AliasStrategy, DefaultImportTracker, FileToModuleHost, FileToModuleStrategy, ImportRewriter, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NoopImportRewriter, R3SymbolsImportRewriter, Reference, ReferenceEmitter} from './imports';
import {IncrementalState} from './incremental';
import {PartialEvaluator} from './partial_evaluator';
import {AbsoluteFsPath, LogicalFileSystem} from './path';
import {NOOP_PERF_RECORDER, PerfRecorder, PerfTracker} from './perf';
@ -60,6 +61,7 @@ export class NgtscProgram implements api.Program {
private defaultImportTracker: DefaultImportTracker;
private perfRecorder: PerfRecorder = NOOP_PERF_RECORDER;
private perfTracker: PerfTracker|null = null;
private incrementalState: IncrementalState;
constructor(
rootNames: ReadonlyArray<string>, private options: api.CompilerOptions,
@ -143,6 +145,13 @@ export class NgtscProgram implements api.Program {
this.moduleResolver = new ModuleResolver(this.tsProgram, options, this.host);
this.cycleAnalyzer = new CycleAnalyzer(new ImportGraph(this.moduleResolver));
this.defaultImportTracker = new DefaultImportTracker();
if (oldProgram === undefined) {
this.incrementalState = IncrementalState.fresh();
} else {
const oldNgtscProgram = oldProgram as NgtscProgram;
this.incrementalState = IncrementalState.reconcile(
oldNgtscProgram.incrementalState, oldNgtscProgram.tsProgram, this.tsProgram);
}
}
getTsProgram(): ts.Program { return this.tsProgram; }
@ -332,6 +341,10 @@ export class NgtscProgram implements api.Program {
continue;
}
if (this.incrementalState.safeToSkipEmit(targetSourceFile)) {
continue;
}
const fileEmitSpan = this.perfRecorder.start('emitFile', targetSourceFile);
emitResults.push(emitCallback({
targetSourceFile,
@ -440,8 +453,8 @@ export class NgtscProgram implements api.Program {
];
return new IvyCompilation(
handlers, checker, this.reflector, this.importRewriter, this.perfRecorder,
this.sourceToFactorySymbols);
handlers, checker, this.reflector, this.importRewriter, this.incrementalState,
this.perfRecorder, this.sourceToFactorySymbols);
}
private get reflector(): TypeScriptReflectionHost {