diff --git a/packages/angular/build/src/builders/application/build-action.ts b/packages/angular/build/src/builders/application/build-action.ts index c9089eed4ede..96b6c8dd2980 100644 --- a/packages/angular/build/src/builders/application/build-action.ts +++ b/packages/angular/build/src/builders/application/build-action.ts @@ -223,7 +223,10 @@ async function emitOutputResult( } // Template updates only exist if no other changes have occurred + // To support Tailwind CSS the global styles.css build output is included in the update so it can be checked for changes + // as the file watcher is only capable of detecting changes to the raw styles.css file. if (templateUpdates?.size) { + const globalStyles = outputFiles.find((f) => f.path === 'styles.css'); const updateResult: ComponentUpdateResult = { kind: ResultKind.ComponentUpdate, updates: Array.from(templateUpdates).map(([id, content]) => ({ @@ -231,6 +234,14 @@ async function emitOutputResult( id, content, })), + globalStyles: globalStyles + ? { + origin: 'memory', + hash: globalStyles.hash, + type: globalStyles.type, + contents: globalStyles.contents, + } + : undefined, }; return updateResult; diff --git a/packages/angular/build/src/builders/application/results.ts b/packages/angular/build/src/builders/application/results.ts index 842af17dda3f..8e18187f96e6 100644 --- a/packages/angular/build/src/builders/application/results.ts +++ b/packages/angular/build/src/builders/application/results.ts @@ -73,4 +73,5 @@ export interface ComponentUpdateResult extends BaseResult { type: 'style' | 'template'; content: string; }[]; + globalStyles?: MemoryFile; } diff --git a/packages/angular/build/src/builders/dev-server/vite-server.ts b/packages/angular/build/src/builders/dev-server/vite-server.ts index f3309d94f6d9..214aadca2531 100644 --- a/packages/angular/build/src/builders/dev-server/vite-server.ts +++ b/packages/angular/build/src/builders/dev-server/vite-server.ts @@ -27,7 +27,7 @@ import { EsbuildLoaderOption, getDepOptimizationConfig } from '../../tools/vite/ import { loadProxyConfiguration, normalizeSourceMaps } from '../../utils'; import { useComponentStyleHmr, useComponentTemplateHmr } from '../../utils/environment-options'; import { loadEsmModule } from '../../utils/load-esm'; -import { Result, ResultFile, ResultKind } from '../application/results'; +import { MemoryFile, Result, ResultFile, ResultKind } from '../application/results'; import { type ApplicationBuilderInternalOptions, BuildOutputFileType, @@ -265,6 +265,11 @@ export async function* serveWithVite( }); } } + + if (result.globalStyles) { + updateGlobalStyles(result.globalStyles, generatedFiles, server); + } + context.logger.info('Component update sent to client(s).'); continue; default: @@ -611,6 +616,37 @@ function analyzeResultFiles( } } +function updateGlobalStyles( + file: MemoryFile, + generatedFiles: Map, + server: ViteDevServer, +) { + const stylesUrl = '/styles.css'; + const styleHash = generatedFiles.get(stylesUrl); + if (file.hash !== styleHash?.hash) { + generatedFiles.set(stylesUrl, { + contents: file.contents, + size: file.contents.byteLength, + hash: file.hash, + updated: true, + type: file.type, + servable: true, + }); + const timestamp = Date.now(); + server.ws.send({ + type: 'update', + updates: [ + { + type: 'css-update' as const, + timestamp, + path: stylesUrl, + acceptedPath: stylesUrl, + }, + ], + }); + } +} + export async function setupServer( serverOptions: NormalizedDevServerOptions, outputFiles: Map,