@@ -147,6 +147,8 @@ export async function* serveWithVite(
147147 browserOptions . templateUpdates =
148148 serverOptions . liveReload && serverOptions . hmr && useComponentTemplateHmr ;
149149
150+ browserOptions . incrementalResults = true ;
151+
150152 // Setup the prebundling transformer that will be shared across Vite prebundling requests
151153 const prebundleTransformer = new JavaScriptTransformer (
152154 // Always enable JIT linking to support applications built with and without AOT.
@@ -225,10 +227,24 @@ export async function* serveWithVite(
225227 }
226228
227229 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 ;
229234 if ( file . origin === 'disk' ) {
230235 assetFiles . set ( '/' + normalizePath ( outputPath ) , normalizePath ( file . inputPath ) ) ;
236+ continue ;
231237 }
238+
239+ updateResultRecord (
240+ entry ,
241+ normalizePath ,
242+ htmlIndexPath ,
243+ generatedFiles ,
244+ componentStyles ,
245+ // The initial build will not yet have a server setup
246+ ! server ,
247+ ) ;
232248 }
233249
234250 // Invalidate SSR module graph to ensure that only new rebuild is used and not stale component updates
@@ -239,18 +255,34 @@ export async function* serveWithVite(
239255 // Clear stale template updates on code rebuilds
240256 templateUpdates . clear ( ) ;
241257
242- // Analyze result files for changes
243- analyzeResultFiles (
244- normalizePath ,
245- htmlIndexPath ,
246- result . files ,
247- generatedFiles ,
248- componentStyles ,
249- ) ;
250258 break ;
251259 case ResultKind . Incremental :
252260 assert ( server , 'Builder must provide an initial full build before incremental results.' ) ;
253- // TODO: Implement support -- application builder currently does not use
261+
262+ for ( const removed of result . removed ) {
263+ const filePath = '/' + normalizePath ( removed . path ) ;
264+ generatedFiles . delete ( filePath ) ;
265+ assetFiles . delete ( filePath ) ;
266+ }
267+ for ( const modified of result . modified ) {
268+ updateResultRecord (
269+ [ modified , result . files [ modified ] ] ,
270+ normalizePath ,
271+ htmlIndexPath ,
272+ generatedFiles ,
273+ componentStyles ,
274+ ) ;
275+ }
276+ for ( const added of result . added ) {
277+ updateResultRecord (
278+ [ added , result . files [ added ] ] ,
279+ normalizePath ,
280+ htmlIndexPath ,
281+ generatedFiles ,
282+ componentStyles ,
283+ ) ;
284+ }
285+
254286 break ;
255287 case ResultKind . ComponentUpdate :
256288 assert ( serverOptions . hmr , 'Component updates are only supported with HMR enabled.' ) ;
@@ -444,12 +476,13 @@ async function handleUpdate(
444476 let destroyAngularServerAppCalled = false ;
445477
446478 // Invalidate any updated files
447- for ( const [ file , { updated , type } ] of generatedFiles ) {
448- if ( ! updated ) {
479+ for ( const [ file , record ] of generatedFiles ) {
480+ if ( ! record . updated ) {
449481 continue ;
450482 }
483+ record . updated = false ;
451484
452- if ( type === BuildOutputFileType . ServerApplication && ! destroyAngularServerAppCalled ) {
485+ if ( record . type === BuildOutputFileType . ServerApplication && ! destroyAngularServerAppCalled ) {
453486 // Clear the server app cache
454487 // This must be done before module invalidation.
455488 const { ɵdestroyAngularServerApp } = ( await server . ssrLoadModule ( '/main.server.mjs' ) ) as {
@@ -541,85 +574,66 @@ async function handleUpdate(
541574 }
542575}
543576
544- function analyzeResultFiles (
577+ function updateResultRecord (
578+ resultFile : [ outpuPath : string , file : ResultFile ] ,
545579 normalizePath : ( id : string ) => string ,
546580 htmlIndexPath : string ,
547- resultFiles : Record < string , ResultFile > ,
548581 generatedFiles : Map < string , OutputFileRecord > ,
549582 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- }
583+ initial = false ,
584+ ) : void {
585+ const [ outputPath , file ] = resultFile ;
564586
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+ if ( file . origin === 'disk' ) {
588+ return ;
589+ }
580590
581- continue ;
582- }
591+ let filePath ;
592+ if ( outputPath === htmlIndexPath ) {
593+ // Convert custom index output path to standard index path for dev-server usage.
594+ // This mimics the Webpack dev-server behavior.
595+ filePath = '/index.html' ;
596+ } else {
597+ filePath = '/' + normalizePath ( outputPath ) ;
598+ }
583599
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- }
600+ const servable =
601+ file . type === BuildOutputFileType . Browser || file . type === BuildOutputFileType . Media ;
594602
595- // New or updated file
603+ // Skip analysis of sourcemaps
604+ if ( filePath . endsWith ( '.map' ) ) {
596605 generatedFiles . set ( filePath , {
597606 contents : file . contents ,
607+ servable,
598608 size : file . contents . byteLength ,
599609 hash : file . hash ,
600- updated : true ,
601610 type : file . type ,
602- servable ,
611+ updated : false ,
603612 } ) ;
604613
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- }
614+ return ;
616615 }
617616
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 ) ;
617+ // New or updated file
618+ generatedFiles . set ( filePath , {
619+ contents : file . contents ,
620+ size : file . contents . byteLength ,
621+ hash : file . hash ,
622+ // Consider the files updated except on the initial build result
623+ updated : ! initial ,
624+ type : file . type ,
625+ servable,
626+ } ) ;
627+
628+ // Record any external component styles
629+ if ( filePath . endsWith ( '.css' ) && / ^ \/ [ a - f 0 - 9 ] { 64 } \. c s s $ / . test ( filePath ) ) {
630+ const componentStyle = componentStyles . get ( filePath ) ;
631+ if ( componentStyle ) {
632+ componentStyle . rawContent = file . contents ;
633+ } else {
634+ componentStyles . set ( filePath , {
635+ rawContent : file . contents ,
636+ } ) ;
623637 }
624638 }
625639}
0 commit comments