@@ -147,6 +147,8 @@ export async function* serveWithVite(
147
147
browserOptions . templateUpdates =
148
148
serverOptions . liveReload && serverOptions . hmr && useComponentTemplateHmr ;
149
149
150
+ browserOptions . incrementalResults = true ;
151
+
150
152
// Setup the prebundling transformer that will be shared across Vite prebundling requests
151
153
const prebundleTransformer = new JavaScriptTransformer (
152
154
// Always enable JIT linking to support applications built with and without AOT.
@@ -225,10 +227,25 @@ export async function* serveWithVite(
225
227
}
226
228
227
229
assetFiles . clear ( ) ;
228
- for ( const [ outputPath , file ] of Object . entries ( result . files ) ) {
230
+ componentStyles . clear ( ) ;
231
+ generatedFiles . clear ( ) ;
232
+ for ( const entry of Object . entries ( result . files ) ) {
233
+ const [ outputPath , file ] = entry ;
229
234
if ( file . origin === 'disk' ) {
230
235
assetFiles . set ( '/' + normalizePath ( outputPath ) , normalizePath ( file . inputPath ) ) ;
236
+ continue ;
231
237
}
238
+
239
+ updateResultRecord (
240
+ outputPath ,
241
+ file ,
242
+ normalizePath ,
243
+ htmlIndexPath ,
244
+ generatedFiles ,
245
+ componentStyles ,
246
+ // The initial build will not yet have a server setup
247
+ ! server ,
248
+ ) ;
232
249
}
233
250
234
251
// Invalidate SSR module graph to ensure that only new rebuild is used and not stale component updates
@@ -239,18 +256,36 @@ export async function* serveWithVite(
239
256
// Clear stale template updates on code rebuilds
240
257
templateUpdates . clear ( ) ;
241
258
242
- // Analyze result files for changes
243
- analyzeResultFiles (
244
- normalizePath ,
245
- htmlIndexPath ,
246
- result . files ,
247
- generatedFiles ,
248
- componentStyles ,
249
- ) ;
250
259
break ;
251
260
case ResultKind . Incremental :
252
261
assert ( server , 'Builder must provide an initial full build before incremental results.' ) ;
253
- // TODO: Implement support -- application builder currently does not use
262
+
263
+ for ( const removed of result . removed ) {
264
+ const filePath = '/' + normalizePath ( removed . path ) ;
265
+ generatedFiles . delete ( filePath ) ;
266
+ assetFiles . delete ( filePath ) ;
267
+ }
268
+ for ( const modified of result . modified ) {
269
+ updateResultRecord (
270
+ modified ,
271
+ result . files [ modified ] ,
272
+ normalizePath ,
273
+ htmlIndexPath ,
274
+ generatedFiles ,
275
+ componentStyles ,
276
+ ) ;
277
+ }
278
+ for ( const added of result . added ) {
279
+ updateResultRecord (
280
+ added ,
281
+ result . files [ added ] ,
282
+ normalizePath ,
283
+ htmlIndexPath ,
284
+ generatedFiles ,
285
+ componentStyles ,
286
+ ) ;
287
+ }
288
+
254
289
break ;
255
290
case ResultKind . ComponentUpdate :
256
291
assert ( serverOptions . hmr , 'Component updates are only supported with HMR enabled.' ) ;
@@ -444,12 +479,13 @@ async function handleUpdate(
444
479
let destroyAngularServerAppCalled = false ;
445
480
446
481
// Invalidate any updated files
447
- for ( const [ file , { updated , type } ] of generatedFiles ) {
448
- if ( ! updated ) {
482
+ for ( const [ file , record ] of generatedFiles ) {
483
+ if ( ! record . updated ) {
449
484
continue ;
450
485
}
486
+ record . updated = false ;
451
487
452
- if ( type === BuildOutputFileType . ServerApplication && ! destroyAngularServerAppCalled ) {
488
+ if ( record . type === BuildOutputFileType . ServerApplication && ! destroyAngularServerAppCalled ) {
453
489
// Clear the server app cache
454
490
// This must be done before module invalidation.
455
491
const { ɵdestroyAngularServerApp } = ( await server . ssrLoadModule ( '/main.server.mjs' ) ) as {
@@ -541,85 +577,65 @@ async function handleUpdate(
541
577
}
542
578
}
543
579
544
- function analyzeResultFiles (
580
+ function updateResultRecord (
581
+ outputPath : string ,
582
+ file : ResultFile ,
545
583
normalizePath : ( id : string ) => string ,
546
584
htmlIndexPath : string ,
547
- resultFiles : Record < string , ResultFile > ,
548
585
generatedFiles : Map < string , OutputFileRecord > ,
549
586
componentStyles : Map < string , ComponentStyleRecord > ,
550
- ) {
551
- const seen = new Set < string > ( [ '/index.html' ] ) ;
552
- for ( const [ outputPath , file ] of Object . entries ( resultFiles ) ) {
553
- if ( file . origin === 'disk' ) {
554
- continue ;
555
- }
556
- let filePath ;
557
- if ( outputPath === htmlIndexPath ) {
558
- // Convert custom index output path to standard index path for dev-server usage.
559
- // This mimics the Webpack dev-server behavior.
560
- filePath = '/index.html' ;
561
- } else {
562
- filePath = '/' + normalizePath ( outputPath ) ;
563
- }
564
-
565
- seen . add ( filePath ) ;
566
-
567
- const servable =
568
- file . type === BuildOutputFileType . Browser || file . type === BuildOutputFileType . Media ;
569
-
570
- // Skip analysis of sourcemaps
571
- if ( filePath . endsWith ( '.map' ) ) {
572
- generatedFiles . set ( filePath , {
573
- contents : file . contents ,
574
- servable,
575
- size : file . contents . byteLength ,
576
- hash : file . hash ,
577
- type : file . type ,
578
- updated : false ,
579
- } ) ;
587
+ initial = false ,
588
+ ) : void {
589
+ if ( file . origin === 'disk' ) {
590
+ return ;
591
+ }
580
592
581
- continue ;
582
- }
593
+ let filePath ;
594
+ if ( outputPath === htmlIndexPath ) {
595
+ // Convert custom index output path to standard index path for dev-server usage.
596
+ // This mimics the Webpack dev-server behavior.
597
+ filePath = '/index.html' ;
598
+ } else {
599
+ filePath = '/' + normalizePath ( outputPath ) ;
600
+ }
583
601
584
- const existingRecord = generatedFiles . get ( filePath ) ;
585
- if (
586
- existingRecord &&
587
- existingRecord . size === file . contents . byteLength &&
588
- existingRecord . hash === file . hash
589
- ) {
590
- // Same file
591
- existingRecord . updated = false ;
592
- continue ;
593
- }
602
+ const servable =
603
+ file . type === BuildOutputFileType . Browser || file . type === BuildOutputFileType . Media ;
594
604
595
- // New or updated file
605
+ // Skip analysis of sourcemaps
606
+ if ( filePath . endsWith ( '.map' ) ) {
596
607
generatedFiles . set ( filePath , {
597
608
contents : file . contents ,
609
+ servable,
598
610
size : file . contents . byteLength ,
599
611
hash : file . hash ,
600
- updated : true ,
601
612
type : file . type ,
602
- servable ,
613
+ updated : false ,
603
614
} ) ;
604
615
605
- // Record any external component styles
606
- if ( filePath . endsWith ( '.css' ) && / ^ \/ [ a - f 0 - 9 ] { 64 } \. c s s $ / . test ( filePath ) ) {
607
- const componentStyle = componentStyles . get ( filePath ) ;
608
- if ( componentStyle ) {
609
- componentStyle . rawContent = file . contents ;
610
- } else {
611
- componentStyles . set ( filePath , {
612
- rawContent : file . contents ,
613
- } ) ;
614
- }
615
- }
616
+ return ;
616
617
}
617
618
618
- // Clear stale output files
619
- for ( const file of generatedFiles . keys ( ) ) {
620
- if ( ! seen . has ( file ) ) {
621
- generatedFiles . delete ( file ) ;
622
- componentStyles . delete ( file ) ;
619
+ // New or updated file
620
+ generatedFiles . set ( filePath , {
621
+ contents : file . contents ,
622
+ size : file . contents . byteLength ,
623
+ hash : file . hash ,
624
+ // Consider the files updated except on the initial build result
625
+ updated : ! initial ,
626
+ type : file . type ,
627
+ servable,
628
+ } ) ;
629
+
630
+ // Record any external component styles
631
+ if ( filePath . endsWith ( '.css' ) && / ^ \/ [ a - f 0 - 9 ] { 64 } \. c s s $ / . test ( filePath ) ) {
632
+ const componentStyle = componentStyles . get ( filePath ) ;
633
+ if ( componentStyle ) {
634
+ componentStyle . rawContent = file . contents ;
635
+ } else {
636
+ componentStyles . set ( filePath , {
637
+ rawContent : file . contents ,
638
+ } ) ;
623
639
}
624
640
}
625
641
}
0 commit comments