Skip to content

Commit 96d604f

Browse files
committed
refactor(@angular/build): add initial infrastructure to support inline template HMR
The Angular AOT compilation logic for a rebuild has been updated to include infrastructure for additional checks of stale TypeScript files against updated files. The actual comparison aspects have not yet been implement and no behavior changes are yet present for template HMR.
1 parent 8c534da commit 96d604f

File tree

1 file changed

+54
-13
lines changed

1 file changed

+54
-13
lines changed

packages/angular/build/src/tools/angular/compilation/aot-compilation.ts

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,18 @@ export class AotCompilation extends AngularCompilation {
6666
hostOptions.externalStylesheets ??= new Map();
6767
}
6868

69+
// Collect stale source files for HMR analysis of inline component resources
70+
let staleSourceFiles;
71+
if (compilerOptions['_enableHmr'] && hostOptions.modifiedFiles && this.#state) {
72+
for (const modifiedFile of hostOptions.modifiedFiles) {
73+
const sourceFile = this.#state.typeScriptProgram.getSourceFile(modifiedFile);
74+
if (sourceFile) {
75+
staleSourceFiles ??= new Map<string, ts.SourceFile>();
76+
staleSourceFiles.set(modifiedFile, sourceFile);
77+
}
78+
}
79+
}
80+
6981
// Create Angular compiler host
7082
const host = createAngularCompilerHost(ts, compilerOptions, hostOptions);
7183

@@ -95,14 +107,12 @@ export class AotCompilation extends AngularCompilation {
95107
await profileAsync('NG_ANALYZE_PROGRAM', () => angularCompiler.analyzeAsync());
96108

97109
let templateUpdates;
98-
if (
99-
compilerOptions['_enableHmr'] &&
100-
hostOptions.modifiedFiles &&
101-
hasOnlyTemplates(hostOptions.modifiedFiles)
102-
) {
103-
const componentNodes = [...hostOptions.modifiedFiles].flatMap((file) => [
104-
...angularCompiler.getComponentsWithTemplateFile(file),
105-
]);
110+
if (compilerOptions['_enableHmr'] && hostOptions.modifiedFiles && this.#state) {
111+
const componentNodes = collectHmrCandidates(
112+
hostOptions.modifiedFiles,
113+
angularProgram,
114+
staleSourceFiles,
115+
);
106116

107117
for (const node of componentNodes) {
108118
if (!ts.isClassDeclaration(node)) {
@@ -423,15 +433,46 @@ function findAffectedFiles(
423433
return affectedFiles;
424434
}
425435

426-
function hasOnlyTemplates(modifiedFiles: Set<string>): boolean {
436+
function collectHmrCandidates(
437+
modifiedFiles: Set<string>,
438+
{ compiler }: ng.NgtscProgram,
439+
staleSourceFiles: Map<string, ts.SourceFile> | undefined,
440+
): Set<ts.ClassDeclaration> {
441+
const candidates = new Set<ts.ClassDeclaration>();
442+
427443
for (const file of modifiedFiles) {
428-
const lowerFile = file.toLowerCase();
429-
if (lowerFile.endsWith('.html') || lowerFile.endsWith('.svg')) {
444+
const templateFileNodes = compiler.getComponentsWithTemplateFile(file);
445+
if (templateFileNodes.size) {
446+
templateFileNodes.forEach((node) => candidates.add(node as ts.ClassDeclaration));
447+
continue;
448+
}
449+
450+
const styleFileNodes = compiler.getComponentsWithStyleFile(file);
451+
if (styleFileNodes.size) {
452+
styleFileNodes.forEach((node) => candidates.add(node as ts.ClassDeclaration));
430453
continue;
431454
}
432455

433-
return false;
456+
const staleSource = staleSourceFiles?.get(file);
457+
if (staleSource === undefined) {
458+
// Unknown file requires a rebuild so clear out the candidates and stop collecting
459+
candidates.clear();
460+
break;
461+
}
462+
463+
const updatedSource = compiler.getCurrentProgram().getSourceFile(file);
464+
if (updatedSource === undefined) {
465+
// No longer existing program file requires a rebuild so clear out the candidates and stop collecting
466+
candidates.clear();
467+
break;
468+
}
469+
470+
// Compare the stale and updated file for changes
471+
472+
// TODO: Implement -- for now assume a rebuild is needed
473+
candidates.clear();
474+
break;
434475
}
435476

436-
return true;
477+
return candidates;
437478
}

0 commit comments

Comments
 (0)