fix(ivy): recompile component when template changes in ngc watch mode (#33551)
When the Angular compiler is operated through the ngc binary in watch mode, changing a template in an external file would not cause the component to be recompiled if Ivy is enabled. There was a problem with how a cached compiler host was present that was unaware of the changed resources, therefore failing to trigger a recompilation of a component whenever its template changes. This commit fixes the issue by ensuring that information about modified resources is correctly available to the cached compiler host. Fixes #32869 PR Close #33551
This commit is contained in:
parent
8d72a37f3e
commit
8912b11f56
|
@ -153,7 +153,7 @@ export function performWatchCompilation(host: PerformWatchHost):
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked to perform initial compilation or re-compilation in watch mode
|
// Invoked to perform initial compilation or re-compilation in watch mode
|
||||||
function doCompilation(modifiedResourceFiles?: Set<string>): Diagnostics {
|
function doCompilation(): Diagnostics {
|
||||||
if (!cachedOptions) {
|
if (!cachedOptions) {
|
||||||
cachedOptions = host.readConfiguration();
|
cachedOptions = host.readConfiguration();
|
||||||
}
|
}
|
||||||
|
@ -197,8 +197,12 @@ export function performWatchCompilation(host: PerformWatchHost):
|
||||||
return ce.content !;
|
return ce.content !;
|
||||||
};
|
};
|
||||||
// Provide access to the file paths that triggered this rebuild
|
// Provide access to the file paths that triggered this rebuild
|
||||||
cachedCompilerHost.getModifiedResourceFiles =
|
cachedCompilerHost.getModifiedResourceFiles = function() {
|
||||||
modifiedResourceFiles !== undefined ? () => modifiedResourceFiles : undefined;
|
if (timerHandleForRecompilation === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return timerHandleForRecompilation.modifiedResourceFiles;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
ignoreFilesForWatch.clear();
|
ignoreFilesForWatch.clear();
|
||||||
const oldProgram = cachedProgram;
|
const oldProgram = cachedProgram;
|
||||||
|
@ -287,7 +291,7 @@ export function performWatchCompilation(host: PerformWatchHost):
|
||||||
function recompile() {
|
function recompile() {
|
||||||
host.reportDiagnostics(
|
host.reportDiagnostics(
|
||||||
[createMessageDiagnostic('File change detected. Starting incremental compilation.')]);
|
[createMessageDiagnostic('File change detected. Starting incremental compilation.')]);
|
||||||
doCompilation(timerHandleForRecompilation !.modifiedResourceFiles);
|
doCompilation();
|
||||||
timerHandleForRecompilation = undefined;
|
timerHandleForRecompilation = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,7 @@ ts_library(
|
||||||
":test_utils",
|
":test_utils",
|
||||||
"//packages/compiler",
|
"//packages/compiler",
|
||||||
"//packages/compiler-cli",
|
"//packages/compiler-cli",
|
||||||
|
"//packages/private/testing",
|
||||||
"@npm//typescript",
|
"@npm//typescript",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {ivyEnabled} from '@angular/private/testing';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
@ -24,8 +25,8 @@ describe('perform watch', () => {
|
||||||
outDir = path.resolve(testSupport.basePath, 'outDir');
|
outDir = path.resolve(testSupport.basePath, 'outDir');
|
||||||
});
|
});
|
||||||
|
|
||||||
function createConfig(): ng.ParsedConfiguration {
|
function createConfig(overrideOptions: ng.CompilerOptions = {}): ng.ParsedConfiguration {
|
||||||
const options = testSupport.createCompilerOptions({outDir});
|
const options = testSupport.createCompilerOptions({outDir, ...overrideOptions});
|
||||||
return {
|
return {
|
||||||
options,
|
options,
|
||||||
rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')],
|
rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')],
|
||||||
|
@ -50,6 +51,33 @@ describe('perform watch', () => {
|
||||||
expect(fs.existsSync(path.resolve(outDir, 'src', 'main.ngfactory.js'))).toBe(true);
|
expect(fs.existsSync(path.resolve(outDir, 'src', 'main.ngfactory.js'))).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should recompile components when its template changes', () => {
|
||||||
|
const config = createConfig({enableIvy: ivyEnabled});
|
||||||
|
const host = new MockWatchHost(config);
|
||||||
|
|
||||||
|
testSupport.writeFiles({
|
||||||
|
'src/main.ts': createModuleAndCompSource('main', './main.html'),
|
||||||
|
'src/main.html': 'initial',
|
||||||
|
'src/index.ts': `export * from './main'; `,
|
||||||
|
});
|
||||||
|
|
||||||
|
const watchResult = performWatchCompilation(host);
|
||||||
|
expectNoDiagnostics(config.options, watchResult.firstCompileResult);
|
||||||
|
|
||||||
|
const htmlPath = path.resolve(testSupport.basePath, 'src', 'main.html');
|
||||||
|
const genPath = ivyEnabled ? path.resolve(outDir, 'src', 'main.js') :
|
||||||
|
path.resolve(outDir, 'src', 'main.ngfactory.js');
|
||||||
|
|
||||||
|
const initial = fs.readFileSync(genPath, {encoding: 'utf8'});
|
||||||
|
expect(initial).toContain('"initial"');
|
||||||
|
|
||||||
|
fs.writeFileSync(htmlPath, 'updated');
|
||||||
|
host.triggerFileChange(FileChangeEvent.Change, htmlPath);
|
||||||
|
|
||||||
|
const updated = fs.readFileSync(genPath, {encoding: 'utf8'});
|
||||||
|
expect(updated).toContain('"updated"');
|
||||||
|
});
|
||||||
|
|
||||||
it('should cache files on subsequent runs', () => {
|
it('should cache files on subsequent runs', () => {
|
||||||
const config = createConfig();
|
const config = createConfig();
|
||||||
const host = new MockWatchHost(config);
|
const host = new MockWatchHost(config);
|
||||||
|
|
Loading…
Reference in New Issue