fix(ivy): ensure that changes to component resources trigger incremental builds (#30954)
Optimizations to skip compiling source files that had not changed did not account for the case where only a resource file changes, such as an external template or style file. Now we track such dependencies and trigger a recompilation if any of the previously tracked resources have changed. This will require a change on the CLI side to provide the list of resource files that changed to trigger the current compilation by implementing `CompilerHost.getModifiedResourceFiles()`. Closes #30947 PR Close #30954
This commit is contained in:

committed by
Kara Erickson

parent
dc613b336d
commit
48def92cad
@ -8,6 +8,7 @@ ts_library(
|
||||
"//packages/compiler",
|
||||
"//packages/compiler-cli",
|
||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/path",
|
||||
"//packages/compiler-cli/src/ngtsc/routing",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"//packages/compiler-cli/test:test_utils",
|
||||
|
@ -39,6 +39,7 @@ function setupFakeCore(support: TestSupport): void {
|
||||
export class NgtscTestEnvironment {
|
||||
private multiCompileHostExt: MultiCompileHostExt|null = null;
|
||||
private oldProgram: Program|null = null;
|
||||
private changedResources: Set<string>|undefined = undefined;
|
||||
|
||||
private constructor(private support: TestSupport, readonly outDir: string) {}
|
||||
|
||||
@ -106,6 +107,7 @@ export class NgtscTestEnvironment {
|
||||
}
|
||||
|
||||
enableMultipleCompilations(): void {
|
||||
this.changedResources = new Set();
|
||||
this.multiCompileHostExt = new MultiCompileHostExt();
|
||||
setWrapHostForTest(makeWrapHost(this.multiCompileHostExt));
|
||||
}
|
||||
@ -114,6 +116,7 @@ export class NgtscTestEnvironment {
|
||||
if (this.multiCompileHostExt === null) {
|
||||
throw new Error(`Not tracking written files - call enableMultipleCompilations()`);
|
||||
}
|
||||
this.changedResources !.clear();
|
||||
this.multiCompileHostExt.flushWrittenFileTracking();
|
||||
}
|
||||
|
||||
@ -133,8 +136,9 @@ export class NgtscTestEnvironment {
|
||||
|
||||
write(fileName: string, content: string) {
|
||||
if (this.multiCompileHostExt !== null) {
|
||||
const absFilePath = path.posix.resolve(this.support.basePath, fileName);
|
||||
const absFilePath = path.resolve(this.support.basePath, fileName).replace(/\\/g, '/');
|
||||
this.multiCompileHostExt.invalidate(absFilePath);
|
||||
this.changedResources !.add(absFilePath);
|
||||
}
|
||||
this.support.write(fileName, content);
|
||||
}
|
||||
@ -175,8 +179,9 @@ export class NgtscTestEnvironment {
|
||||
program: this.oldProgram || undefined,
|
||||
};
|
||||
}
|
||||
const exitCode =
|
||||
main(['-p', this.basePath], errorSpy, undefined, customTransformers, reuseProgram);
|
||||
const exitCode = main(
|
||||
['-p', this.basePath], errorSpy, undefined, customTransformers, reuseProgram,
|
||||
this.changedResources);
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
expect(exitCode).toBe(0);
|
||||
if (this.multiCompileHostExt !== null) {
|
||||
|
@ -6,6 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AbsoluteFsPath} from '@angular/compiler-cli/src/ngtsc/path';
|
||||
|
||||
import {NgtscTestEnvironment} from './env';
|
||||
|
||||
describe('ngtsc incremental compilation', () => {
|
||||
@ -69,6 +71,33 @@ describe('ngtsc incremental compilation', () => {
|
||||
expect(written).not.toContain('/component2.js');
|
||||
});
|
||||
|
||||
it('should rebuild components whose templates have changed', () => {
|
||||
env.write('component1.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({selector: 'cmp', templateUrl: './component1.template.html'})
|
||||
export class Cmp1 {}
|
||||
`);
|
||||
env.write('component1.template.html', 'cmp1');
|
||||
env.write('component2.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({selector: 'cmp2', templateUrl: './component2.template.html'})
|
||||
export class Cmp2 {}
|
||||
`);
|
||||
env.write('component2.template.html', 'cmp2');
|
||||
|
||||
env.driveMain();
|
||||
|
||||
// Make a change to Cmp1 template
|
||||
env.flushWrittenFileTracking();
|
||||
env.write('component1.template.html', 'changed');
|
||||
env.driveMain();
|
||||
const written = env.getFilesWrittenSinceLastFlush();
|
||||
expect(written).toContain('/component1.js');
|
||||
expect(written).not.toContain('/component2.js');
|
||||
});
|
||||
|
||||
it('should rebuild components whose partial-evaluation dependencies have changed', () => {
|
||||
env.write('component1.ts', `
|
||||
import {Component} from '@angular/core';
|
||||
@ -222,4 +251,4 @@ function setupFooBarProgram(env: NgtscTestEnvironment) {
|
||||
`);
|
||||
env.driveMain();
|
||||
env.flushWrittenFileTracking();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user