@@ -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,25 @@ 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+ 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+ ) ;
232249 }
233250
234251 // 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(
239256 // Clear stale template updates on code rebuilds
240257 templateUpdates . clear ( ) ;
241258
242- // Analyze result files for changes
243- analyzeResultFiles (
244- normalizePath ,
245- htmlIndexPath ,
246- result . files ,
247- generatedFiles ,
248- componentStyles ,
249- ) ;
250259 break ;
251260 case ResultKind . Incremental :
252261 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+
254289 break ;
255290 case ResultKind . ComponentUpdate :
256291 assert ( serverOptions . hmr , 'Component updates are only supported with HMR enabled.' ) ;
@@ -444,12 +479,13 @@ async function handleUpdate(
444479 let destroyAngularServerAppCalled = false ;
445480
446481 // 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 ) {
449484 continue ;
450485 }
486+ record . updated = false ;
451487
452- if ( type === BuildOutputFileType . ServerApplication && ! destroyAngularServerAppCalled ) {
488+ if ( record . type === BuildOutputFileType . ServerApplication && ! destroyAngularServerAppCalled ) {
453489 // Clear the server app cache
454490 // This must be done before module invalidation.
455491 const { ɵdestroyAngularServerApp } = ( await server . ssrLoadModule ( '/main.server.mjs' ) ) as {
@@ -541,85 +577,65 @@ async function handleUpdate(
541577 }
542578}
543579
544- function analyzeResultFiles (
580+ function updateResultRecord (
581+ outputPath : string ,
582+ file : ResultFile ,
545583 normalizePath : ( id : string ) => string ,
546584 htmlIndexPath : string ,
547- resultFiles : Record < string , ResultFile > ,
548585 generatedFiles : Map < string , OutputFileRecord > ,
549586 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+ }
580592
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+ }
583601
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 ;
594604
595- // New or updated file
605+ // Skip analysis of sourcemaps
606+ if ( filePath . endsWith ( '.map' ) ) {
596607 generatedFiles . set ( filePath , {
597608 contents : file . contents ,
609+ servable,
598610 size : file . contents . byteLength ,
599611 hash : file . hash ,
600- updated : true ,
601612 type : file . type ,
602- servable ,
613+ updated : false ,
603614 } ) ;
604615
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 ;
616617 }
617618
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+ } ) ;
623639 }
624640 }
625641}
0 commit comments