@@ -406,6 +406,7 @@ export async function* serveWithVite(
406
406
key : 'r' ,
407
407
description : 'force reload browser' ,
408
408
action ( server ) {
409
+ usedComponentStyles . clear ( ) ;
409
410
server . ws . send ( {
410
411
type : 'full-reload' ,
411
412
path : '*' ,
@@ -433,7 +434,7 @@ async function handleUpdate(
433
434
server : ViteDevServer ,
434
435
serverOptions : NormalizedDevServerOptions ,
435
436
logger : BuilderContext [ 'logger' ] ,
436
- usedComponentStyles : Map < string , Set < string > > ,
437
+ usedComponentStyles : Map < string , Set < string | boolean > > ,
437
438
) : Promise < void > {
438
439
const updatedFiles : string [ ] = [ ] ;
439
440
let destroyAngularServerAppCalled = false ;
@@ -469,42 +470,57 @@ async function handleUpdate(
469
470
470
471
if ( serverOptions . hmr ) {
471
472
if ( updatedFiles . every ( ( f ) => f . endsWith ( '.css' ) ) ) {
473
+ let requiresReload = false ;
472
474
const timestamp = Date . now ( ) ;
473
- server . ws . send ( {
474
- type : 'update' ,
475
- updates : updatedFiles . flatMap ( ( filePath ) => {
476
- // For component styles, an HMR update must be sent for each one with the corresponding
477
- // component identifier search parameter (`ngcomp`). The Vite client code will not keep
478
- // the existing search parameters when it performs an update and each one must be
479
- // specified explicitly. Typically, there is only one each though as specific style files
480
- // are not typically reused across components.
481
- const componentIds = usedComponentStyles . get ( filePath ) ;
482
- if ( componentIds ) {
483
- return Array . from ( componentIds ) . map ( ( id ) => ( {
484
- type : 'css-update' ,
475
+ const updates = updatedFiles . flatMap ( ( filePath ) => {
476
+ // For component styles, an HMR update must be sent for each one with the corresponding
477
+ // component identifier search parameter (`ngcomp`). The Vite client code will not keep
478
+ // the existing search parameters when it performs an update and each one must be
479
+ // specified explicitly. Typically, there is only one each though as specific style files
480
+ // are not typically reused across components.
481
+ const componentIds = usedComponentStyles . get ( filePath ) ;
482
+ if ( componentIds ) {
483
+ return Array . from ( componentIds ) . map ( ( id ) => {
484
+ if ( id === true ) {
485
+ // Shadow DOM components currently require a full reload.
486
+ // Vite's CSS hot replacement does not support shadow root searching.
487
+ requiresReload = true ;
488
+ }
489
+
490
+ return {
491
+ type : 'css-update' as const ,
485
492
timestamp,
486
- path : `${ filePath } ?ngcomp` + ( id ? `=${ id } ` : '' ) ,
493
+ path : `${ filePath } ?ngcomp` + ( typeof id === 'string' ? `=${ id } ` : '' ) ,
487
494
acceptedPath : filePath ,
488
- } ) ) ;
489
- }
495
+ } ;
496
+ } ) ;
497
+ }
490
498
491
- return {
492
- type : 'css-update' as const ,
493
- timestamp,
494
- path : filePath ,
495
- acceptedPath : filePath ,
496
- } ;
497
- } ) ,
499
+ return {
500
+ type : 'css-update' as const ,
501
+ timestamp,
502
+ path : filePath ,
503
+ acceptedPath : filePath ,
504
+ } ;
498
505
} ) ;
499
506
500
- logger . info ( 'HMR update sent to client(s).' ) ;
507
+ if ( ! requiresReload ) {
508
+ server . ws . send ( {
509
+ type : 'update' ,
510
+ updates,
511
+ } ) ;
512
+ logger . info ( 'HMR update sent to client(s).' ) ;
501
513
502
- return ;
514
+ return ;
515
+ }
503
516
}
504
517
}
505
518
506
519
// Send reload command to clients
507
520
if ( serverOptions . liveReload ) {
521
+ // Clear used component tracking on full reload
522
+ usedComponentStyles . clear ( ) ;
523
+
508
524
server . ws . send ( {
509
525
type : 'full-reload' ,
510
526
path : '*' ,
0 commit comments