@@ -14,6 +14,7 @@ import { readFile } from 'node:fs/promises';
1414import { builtinModules , isBuiltin } from 'node:module' ;
1515import { join } from 'node:path' ;
1616import type { Connect , DepOptimizationConfig , InlineConfig , ViteDevServer } from 'vite' ;
17+ import type { ComponentStyleRecord } from '../../tools/vite/middlewares' ;
1718import {
1819 ServerSsrMode ,
1920 createAngularLocaleDataPlugin ,
@@ -175,7 +176,7 @@ export async function* serveWithVite(
175176 explicitBrowser : [ ] ,
176177 explicitServer : [ ] ,
177178 } ;
178- const usedComponentStyles = new Map < string , Set < string > > ( ) ;
179+ const componentStyles = new Map < string , ComponentStyleRecord > ( ) ;
179180 const templateUpdates = new Map < string , string > ( ) ;
180181
181182 // Add cleanup logic via a builder teardown.
@@ -232,11 +233,17 @@ export async function* serveWithVite(
232233 assetFiles . set ( '/' + normalizePath ( outputPath ) , normalizePath ( file . inputPath ) ) ;
233234 }
234235 }
235- // Clear stale template updates on a code rebuilds
236+ // Clear stale template updates on code rebuilds
236237 templateUpdates . clear ( ) ;
237238
238239 // Analyze result files for changes
239- analyzeResultFiles ( normalizePath , htmlIndexPath , result . files , generatedFiles ) ;
240+ analyzeResultFiles (
241+ normalizePath ,
242+ htmlIndexPath ,
243+ result . files ,
244+ generatedFiles ,
245+ componentStyles ,
246+ ) ;
240247 break ;
241248 case ResultKind . Incremental :
242249 assert ( server , 'Builder must provide an initial full build before incremental results.' ) ;
@@ -321,7 +328,7 @@ export async function* serveWithVite(
321328 server ,
322329 serverOptions ,
323330 context . logger ,
324- usedComponentStyles ,
331+ componentStyles ,
325332 ) ;
326333 }
327334 } else {
@@ -380,7 +387,7 @@ export async function* serveWithVite(
380387 prebundleTransformer ,
381388 target ,
382389 isZonelessApp ( polyfills ) ,
383- usedComponentStyles ,
390+ componentStyles ,
384391 templateUpdates ,
385392 browserOptions . loader as EsbuildLoaderOption | undefined ,
386393 extensions ?. middleware ,
@@ -406,7 +413,7 @@ export async function* serveWithVite(
406413 key : 'r' ,
407414 description : 'force reload browser' ,
408415 action ( server ) {
409- usedComponentStyles . clear ( ) ;
416+ componentStyles . forEach ( ( record ) => record . used ?. clear ( ) ) ;
410417 server . ws . send ( {
411418 type : 'full-reload' ,
412419 path : '*' ,
@@ -434,7 +441,7 @@ async function handleUpdate(
434441 server : ViteDevServer ,
435442 serverOptions : NormalizedDevServerOptions ,
436443 logger : BuilderContext [ 'logger' ] ,
437- usedComponentStyles : Map < string , Set < string | boolean > > ,
444+ componentStyles : Map < string , ComponentStyleRecord > ,
438445) : Promise < void > {
439446 const updatedFiles : string [ ] = [ ] ;
440447 let destroyAngularServerAppCalled = false ;
@@ -478,15 +485,17 @@ async function handleUpdate(
478485 // the existing search parameters when it performs an update and each one must be
479486 // specified explicitly. Typically, there is only one each though as specific style files
480487 // 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- }
488+ const record = componentStyles . get ( filePath ) ;
489+ if ( record ) {
490+ if ( record . reload ) {
491+ // Shadow DOM components currently require a full reload.
492+ // Vite's CSS hot replacement does not support shadow root searching.
493+ requiresReload = true ;
494+
495+ return [ ] ;
496+ }
489497
498+ return Array . from ( record . used ?? [ ] ) . map ( ( id ) => {
490499 return {
491500 type : 'css-update' as const ,
492501 timestamp,
@@ -519,7 +528,7 @@ async function handleUpdate(
519528 // Send reload command to clients
520529 if ( serverOptions . liveReload ) {
521530 // Clear used component tracking on full reload
522- usedComponentStyles . clear ( ) ;
531+ componentStyles . forEach ( ( record ) => record . used ?. clear ( ) ) ;
523532
524533 server . ws . send ( {
525534 type : 'full-reload' ,
@@ -535,6 +544,7 @@ function analyzeResultFiles(
535544 htmlIndexPath : string ,
536545 resultFiles : Record < string , ResultFile > ,
537546 generatedFiles : Map < string , OutputFileRecord > ,
547+ componentStyles : Map < string , ComponentStyleRecord > ,
538548) {
539549 const seen = new Set < string > ( [ '/index.html' ] ) ;
540550 for ( const [ outputPath , file ] of Object . entries ( resultFiles ) ) {
@@ -589,12 +599,25 @@ function analyzeResultFiles(
589599 type : file . type ,
590600 servable,
591601 } ) ;
602+
603+ // Record any external component styles
604+ if ( filePath . endsWith ( '.css' ) && / ^ \/ [ a - f 0 - 9 ] { 64 } \. c s s $ / . test ( filePath ) ) {
605+ const componentStyle = componentStyles . get ( filePath ) ;
606+ if ( componentStyle ) {
607+ componentStyle . rawContent = file . contents ;
608+ } else {
609+ componentStyles . set ( filePath , {
610+ rawContent : file . contents ,
611+ } ) ;
612+ }
613+ }
592614 }
593615
594616 // Clear stale output files
595617 for ( const file of generatedFiles . keys ( ) ) {
596618 if ( ! seen . has ( file ) ) {
597619 generatedFiles . delete ( file ) ;
620+ componentStyles . delete ( file ) ;
598621 }
599622 }
600623}
@@ -609,7 +632,7 @@ export async function setupServer(
609632 prebundleTransformer : JavaScriptTransformer ,
610633 target : string [ ] ,
611634 zoneless : boolean ,
612- usedComponentStyles : Map < string , Set < string > > ,
635+ componentStyles : Map < string , ComponentStyleRecord > ,
613636 templateUpdates : Map < string , string > ,
614637 prebundleLoaderExtensions : EsbuildLoaderOption | undefined ,
615638 extensionMiddleware ?: Connect . NextHandleFunction [ ] ,
@@ -719,7 +742,7 @@ export async function setupServer(
719742 assets,
720743 indexHtmlTransformer,
721744 extensionMiddleware,
722- usedComponentStyles ,
745+ componentStyles ,
723746 templateUpdates,
724747 ssrMode,
725748 } ) ,
0 commit comments