@@ -81,6 +81,7 @@ export class BundlerContext {
8181 #optionsFactory: BundlerOptionsFactory < BuildOptions & { metafile : true ; write : false } > ;
8282 #shouldCacheResult: boolean ;
8383 #loadCache?: LoadResultCache ;
84+ #loadCacheKeys?: Set < string > ;
8485 #invalidationEpoch = 0 ;
8586 readonly watchFiles = new Set < string > ( ) ;
8687
@@ -222,16 +223,34 @@ export class BundlerContext {
222223
223224 // eslint-disable-next-line max-lines-per-function
224225 async #performBundle( ) : Promise < BundleContextResult > {
226+ this . #loadCacheKeys?. clear ( ) ;
227+
225228 // Create esbuild options if not present
226229 if ( this . #esbuildOptions === undefined ) {
227230 if ( this . incremental && ! this . #loadCache) {
228231 this . #loadCache = new MemoryLoadResultCache ( ) ;
229232 }
230- this . #esbuildOptions = this . #optionsFactory( this . #loadCache) ;
231- }
232-
233- if ( this . incremental ) {
234- this . watchFiles . clear ( ) ;
233+ const loadCache = this . #loadCache;
234+ const scopedLoadCache : LoadResultCache | undefined =
235+ this . incremental && loadCache
236+ ? {
237+ get : ( path ) => {
238+ ( this . #loadCacheKeys ??= new Set ( ) ) . add ( path ) ;
239+
240+ return loadCache . get ( path ) ;
241+ } ,
242+ put : ( path , result ) => {
243+ ( this . #loadCacheKeys ??= new Set ( ) ) . add ( path ) ;
244+
245+ return loadCache . put ( path , result ) ;
246+ } ,
247+ invalidate : ( path ) => loadCache . invalidate ( path ) ,
248+ get watchFiles ( ) {
249+ return loadCache . watchFiles ;
250+ } ,
251+ }
252+ : loadCache ;
253+ this . #esbuildOptions = this . #optionsFactory( scopedLoadCache ) ;
235254 }
236255
237256 let result : BuildResult < { metafile : true ; write : false } > ;
@@ -263,7 +282,7 @@ export class BundlerContext {
263282 // Build failures will throw an exception which contains errors/warnings
264283 if ( isEsBuildFailure ( failure ) ) {
265284 this . #addErrorsToWatch( failure ) ;
266- this . #addLoadCacheFilesToWatch( ) ;
285+ await this . #addLoadCacheFilesToWatch( ) ;
267286
268287 return failure ;
269288 } else {
@@ -275,6 +294,8 @@ export class BundlerContext {
275294 // While this should technically not be linked to incremental mode, incremental is only
276295 // currently enabled with watch mode where watch files are needed.
277296 if ( this . incremental ) {
297+ this . watchFiles . clear ( ) ;
298+
278299 // Add input files except virtual angular files which do not exist on disk
279300 for ( const input of Object . keys ( result . metafile . inputs ) ) {
280301 const isInternal = isInternalAngularFile ( input ) || isInternalBundlerFile ( input ) ;
@@ -309,7 +330,7 @@ export class BundlerContext {
309330 // Return if the build encountered any errors
310331 if ( result . errors . length ) {
311332 this . #addErrorsToWatch( result ) ;
312- this . #addLoadCacheFilesToWatch( ) ;
333+ await this . #addLoadCacheFilesToWatch( ) ;
313334
314335 return {
315336 errors : result . errors ,
@@ -425,12 +446,26 @@ export class BundlerContext {
425446 }
426447
427448 #addErrorsToWatch( result : BuildFailure | BuildResult ) : void {
449+ const entryPoints = this . #esbuildOptions?. entryPoints ;
450+ if ( entryPoints ) {
451+ const entries = Array . isArray ( entryPoints )
452+ ? entryPoints . map ( ( entry ) => ( typeof entry === 'string' ? entry : entry . in ) )
453+ : Object . values ( entryPoints ) ;
454+ for ( const entry of entries ) {
455+ if ( isInternalAngularFile ( entry ) || isInternalBundlerFile ( entry ) ) {
456+ continue ;
457+ }
458+
459+ this . watchFiles . add ( isAbsolute ( entry ) ? normalize ( entry ) : join ( this . workspaceRoot , entry ) ) ;
460+ }
461+ }
462+
428463 for ( const error of result . errors ) {
429464 let file = error . location ?. file ;
430465 if ( file && ! isInternalAngularFile ( file ) ) {
431466 this . watchFiles . add ( isAbsolute ( file ) ? normalize ( file ) : join ( this . workspaceRoot , file ) ) ;
432467 }
433- for ( const note of error . notes ) {
468+ for ( const note of error . notes ?? [ ] ) {
434469 file = note . location ?. file ;
435470 if ( file && ! isInternalAngularFile ( file ) ) {
436471 this . watchFiles . add ( isAbsolute ( file ) ? normalize ( file ) : join ( this . workspaceRoot , file ) ) ;
@@ -439,12 +474,24 @@ export class BundlerContext {
439474 }
440475 }
441476
442- #addLoadCacheFilesToWatch( ) : void {
443- if ( this . incremental && this . #loadCache) {
444- for ( const file of this . #loadCache. watchFiles ) {
445- if ( ! isInternalAngularFile ( file ) ) {
446- this . watchFiles . add ( isAbsolute ( file ) ? normalize ( file ) : join ( this . workspaceRoot , file ) ) ;
477+ async #addLoadCacheFilesToWatch( ) : Promise < void > {
478+ const loadCache = this . #loadCache;
479+ if ( ! this . incremental || ! loadCache || ! this . #loadCacheKeys) {
480+ return ;
481+ }
482+
483+ const results = await Promise . all ( Array . from ( this . #loadCacheKeys, ( key ) => loadCache . get ( key ) ) ) ;
484+ for ( const cachedResult of results ) {
485+ if ( ! cachedResult ?. watchFiles ) {
486+ continue ;
487+ }
488+
489+ for ( const file of cachedResult . watchFiles ) {
490+ if ( isInternalAngularFile ( file ) ) {
491+ continue ;
447492 }
493+
494+ this . watchFiles . add ( isAbsolute ( file ) ? normalize ( file ) : join ( this . workspaceRoot , file ) ) ;
448495 }
449496 }
450497 }
@@ -499,30 +546,13 @@ export class BundlerContext {
499546 candidateFiles = normalizedFiles ;
500547 }
501548
502- let invalid = false ;
503- for ( const file of candidateFiles ) {
504- if ( this . #loadCache?. invalidate ( file ) ) {
505- invalid = true ;
549+ if ( this . #loadCache) {
550+ for ( const file of candidateFiles ) {
551+ this . #loadCache. invalidate ( file ) ;
506552 }
507553 }
508554
509- if ( ! invalid ) {
510- if ( this . watchFiles . size < candidateFiles . size ) {
511- for ( const file of this . watchFiles ) {
512- if ( candidateFiles . has ( file ) ) {
513- invalid = true ;
514- break ;
515- }
516- }
517- } else {
518- for ( const file of candidateFiles ) {
519- if ( this . watchFiles . has ( file ) ) {
520- invalid = true ;
521- break ;
522- }
523- }
524- }
525- }
555+ const invalid = ! this . watchFiles . isDisjointFrom ( candidateFiles ) ;
526556
527557 if ( invalid ) {
528558 this . #invalidationEpoch++ ;
@@ -544,6 +574,7 @@ export class BundlerContext {
544574 this . #esbuildResult = undefined ;
545575 this . #activeBundlePromise = undefined ;
546576 this . #loadCache = undefined ;
577+ this . #loadCacheKeys = undefined ;
547578 await this . #esbuildContext?. dispose ( ) ;
548579 } finally {
549580 this . #esbuildContext = undefined ;
0 commit comments