@@ -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