fix(compiler): only don’t emit already emitted files in incremental compilation
This commit is contained in:
parent
f3f4c3d835
commit
caa51950e8
|
@ -318,4 +318,9 @@ export interface Program {
|
|||
* @internal
|
||||
*/
|
||||
getEmittedGeneratedFiles(): Map<string, GeneratedFile>;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getEmittedSourceFiles(): Map<string, ts.SourceFile>;
|
||||
}
|
||||
|
|
|
@ -42,16 +42,17 @@ class AngularCompilerProgram implements Program {
|
|||
private metadataCache: LowerMetadataCache;
|
||||
private oldProgramLibrarySummaries: Map<string, LibrarySummary>|undefined;
|
||||
private oldProgramEmittedGeneratedFiles: Map<string, GeneratedFile>|undefined;
|
||||
private oldProgramEmittedSourceFiles: Map<string, ts.SourceFile>|undefined;
|
||||
// Note: This will be cleared out as soon as we create the _tsProgram
|
||||
private oldTsProgram: ts.Program|undefined;
|
||||
private emittedLibrarySummaries: LibrarySummary[]|undefined;
|
||||
private emittedGeneratedFiles: GeneratedFile[]|undefined;
|
||||
private emittedSourceFiles: ts.SourceFile[]|undefined;
|
||||
|
||||
// Lazily initialized fields
|
||||
private _typeCheckHost: TypeCheckHost;
|
||||
private _compiler: AotCompiler;
|
||||
private _tsProgram: ts.Program;
|
||||
private _changedNonGenFileNames: string[]|undefined;
|
||||
private _analyzedModules: NgAnalyzedModules|undefined;
|
||||
private _structuralDiagnostics: Diagnostic[]|undefined;
|
||||
private _programWithStubs: ts.Program|undefined;
|
||||
|
@ -69,6 +70,7 @@ class AngularCompilerProgram implements Program {
|
|||
if (oldProgram) {
|
||||
this.oldProgramLibrarySummaries = oldProgram.getLibrarySummaries();
|
||||
this.oldProgramEmittedGeneratedFiles = oldProgram.getEmittedGeneratedFiles();
|
||||
this.oldProgramEmittedSourceFiles = oldProgram.getEmittedSourceFiles();
|
||||
}
|
||||
|
||||
if (options.flatModuleOutFile) {
|
||||
|
@ -114,6 +116,17 @@ class AngularCompilerProgram implements Program {
|
|||
return result;
|
||||
}
|
||||
|
||||
getEmittedSourceFiles(): Map<string, ts.SourceFile> {
|
||||
const result = new Map<string, ts.SourceFile>();
|
||||
if (this.oldProgramEmittedSourceFiles) {
|
||||
this.oldProgramEmittedSourceFiles.forEach((sf, fileName) => result.set(fileName, sf));
|
||||
}
|
||||
if (this.emittedSourceFiles) {
|
||||
this.emittedSourceFiles.forEach((sf) => result.set(sf.fileName, sf));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
getTsProgram(): ts.Program { return this.tsProgram; }
|
||||
|
||||
getTsOptionDiagnostics(cancellationToken?: ts.CancellationToken) {
|
||||
|
@ -192,6 +205,7 @@ class AngularCompilerProgram implements Program {
|
|||
const genFileByFileName = new Map<string, GeneratedFile>();
|
||||
genFiles.forEach(genFile => genFileByFileName.set(genFile.genFileUrl, genFile));
|
||||
this.emittedLibrarySummaries = [];
|
||||
const emittedSourceFiles = [] as ts.SourceFile[];
|
||||
const writeTsFile: ts.WriteFileCallback =
|
||||
(outFileName, outData, writeByteOrderMark, onError?, sourceFiles?) => {
|
||||
const sourceFile = sourceFiles && sourceFiles.length == 1 ? sourceFiles[0] : null;
|
||||
|
@ -199,6 +213,10 @@ class AngularCompilerProgram implements Program {
|
|||
if (sourceFile) {
|
||||
outSrcMapping.push({outFileName: outFileName, sourceFile});
|
||||
genFile = genFileByFileName.get(sourceFile.fileName);
|
||||
if (!sourceFile.isDeclarationFile && !GENERATED_FILES.test(sourceFile.fileName)) {
|
||||
// Note: sourceFile is the transformed sourcefile, not the original one!
|
||||
emittedSourceFiles.push(this.tsProgram.getSourceFile(sourceFile.fileName));
|
||||
}
|
||||
}
|
||||
this.writeFile(outFileName, outData, writeByteOrderMark, onError, genFile, sourceFiles);
|
||||
};
|
||||
|
@ -227,12 +245,11 @@ class AngularCompilerProgram implements Program {
|
|||
let emitResult: ts.EmitResult;
|
||||
let emittedUserTsCount: number;
|
||||
try {
|
||||
const useSingleFileEmit = this._changedNonGenFileNames &&
|
||||
(this._changedNonGenFileNames.length + genTsFiles.length) <
|
||||
MAX_FILE_COUNT_FOR_SINGLE_FILE_EMIT;
|
||||
if (useSingleFileEmit) {
|
||||
const sourceFilesToEmit = this.getSourceFilesForEmit();
|
||||
if (sourceFilesToEmit &&
|
||||
(sourceFilesToEmit.length + genTsFiles.length) < MAX_FILE_COUNT_FOR_SINGLE_FILE_EMIT) {
|
||||
const fileNamesToEmit =
|
||||
[...this._changedNonGenFileNames !, ...genTsFiles.map(gf => gf.genFileUrl)];
|
||||
[...sourceFilesToEmit.map(sf => sf.fileName), ...genTsFiles.map(gf => gf.genFileUrl)];
|
||||
emitResult = mergeEmitResults(
|
||||
fileNamesToEmit.map((fileName) => emitResult = emitCallback({
|
||||
program: this.tsProgram,
|
||||
|
@ -242,7 +259,7 @@ class AngularCompilerProgram implements Program {
|
|||
customTransformers: tsCustomTansformers,
|
||||
targetSourceFile: this.tsProgram.getSourceFile(fileName),
|
||||
})));
|
||||
emittedUserTsCount = this._changedNonGenFileNames !.length;
|
||||
emittedUserTsCount = sourceFilesToEmit.length;
|
||||
} else {
|
||||
emitResult = emitCallback({
|
||||
program: this.tsProgram,
|
||||
|
@ -260,6 +277,7 @@ class AngularCompilerProgram implements Program {
|
|||
sourceFile.referencedFiles = references;
|
||||
}
|
||||
}
|
||||
this.emittedSourceFiles = emittedSourceFiles;
|
||||
|
||||
if (!outSrcMapping.length) {
|
||||
// if no files were emitted by TypeScript, also don't emit .json files
|
||||
|
@ -419,16 +437,6 @@ class AngularCompilerProgram implements Program {
|
|||
sourceFiles.push(sf.fileName);
|
||||
}
|
||||
});
|
||||
if (oldTsProgram) {
|
||||
// TODO(tbosch): if one of the files contains a `const enum`
|
||||
// always emit all files!
|
||||
const changedNonGenFileNames = this._changedNonGenFileNames = [] as string[];
|
||||
tmpProgram.getSourceFiles().forEach(sf => {
|
||||
if (!GENERATED_FILES.test(sf.fileName) && oldTsProgram.getSourceFile(sf.fileName) !== sf) {
|
||||
changedNonGenFileNames.push(sf.fileName);
|
||||
}
|
||||
});
|
||||
}
|
||||
return {tmpProgram, sourceFiles, hostAdapter, rootNames};
|
||||
}
|
||||
|
||||
|
@ -522,6 +530,22 @@ class AngularCompilerProgram implements Program {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns undefined if all files should be emitted.
|
||||
*/
|
||||
private getSourceFilesForEmit(): ts.SourceFile[]|undefined {
|
||||
// TODO(tbosch): if one of the files contains a `const enum`
|
||||
// always emit all files -> return undefined!
|
||||
let sourceFilesToEmit: ts.SourceFile[]|undefined;
|
||||
if (this.oldProgramEmittedSourceFiles) {
|
||||
sourceFilesToEmit = this.tsProgram.getSourceFiles().filter(sf => {
|
||||
const oldFile = this.oldProgramEmittedSourceFiles !.get(sf.fileName);
|
||||
return !sf.isDeclarationFile && !GENERATED_FILES.test(sf.fileName) && sf !== oldFile;
|
||||
});
|
||||
}
|
||||
return sourceFilesToEmit;
|
||||
}
|
||||
|
||||
private generateSemanticDiagnostics(): {ts: ts.Diagnostic[], ng: Diagnostic[]} {
|
||||
return translateDiagnostics(this.typeCheckHost, this.tsProgram.getSemanticDiagnostics());
|
||||
}
|
||||
|
|
|
@ -180,7 +180,7 @@ describe('ng program', () => {
|
|||
// compile libraries
|
||||
const p1 = compile(undefined, options, undefined, host).program;
|
||||
|
||||
// first compile without libraries
|
||||
// compile without libraries
|
||||
const p2 = compile(p1, options, undefined, host).program;
|
||||
expect(written.has(path.resolve(testSupport.basePath, 'built/src/index.js'))).toBe(true);
|
||||
let ngFactoryContent =
|
||||
|
@ -202,11 +202,22 @@ describe('ng program', () => {
|
|||
// change a file that is input to generated files
|
||||
written.clear();
|
||||
testSupport.writeFiles({'src/index.html': 'Hello'});
|
||||
compile(p4, options, undefined, host);
|
||||
const p5 = compile(p4, options, undefined, host).program;
|
||||
expect(written.size).toBe(1);
|
||||
ngFactoryContent =
|
||||
written.get(path.resolve(testSupport.basePath, 'built/src/index.ngfactory.js'));
|
||||
expect(ngFactoryContent).toMatch(/Hello/);
|
||||
|
||||
// change a file and create an intermediate program that is not emitted
|
||||
written.clear();
|
||||
fileCache.delete(path.resolve(testSupport.basePath, 'src/index.ts'));
|
||||
const p6 = ng.createProgram({
|
||||
rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')],
|
||||
options: testSupport.createCompilerOptions(options), host,
|
||||
oldProgram: p5
|
||||
});
|
||||
const p7 = compile(p6, options, undefined, host).program;
|
||||
expect(written.size).toBe(1);
|
||||
});
|
||||
|
||||
it('should set emitSkipped to false for full and incremental emit', () => {
|
||||
|
|
Loading…
Reference in New Issue