@@ -129,6 +129,11 @@ export class AngularServerApp {
129
129
*/
130
130
private boostrap : AngularBootstrap | undefined ;
131
131
132
+ /**
133
+ * Decorder used to convert a string to a Uint8Array.
134
+ */
135
+ private readonly textDecoder = new TextEncoder ( ) ;
136
+
132
137
/**
133
138
* Cache for storing critical CSS for pages.
134
139
* Stores a maximum of MAX_INLINE_CSS_CACHE_ENTRIES entries.
@@ -318,30 +323,46 @@ export class AngularServerApp {
318
323
SERVER_CONTEXT_VALUE [ renderMode ] ,
319
324
) ;
320
325
321
- if ( inlineCriticalCss ) {
322
- // Optionally inline critical CSS.
323
- this . inlineCriticalCssProcessor ??= new InlineCriticalCssProcessor ( ( path : string ) => {
324
- const fileName = path . split ( '/' ) . pop ( ) ?? path ;
325
-
326
- return this . assets . getServerAsset ( fileName ) . text ( ) ;
327
- } ) ;
326
+ if ( ! inlineCriticalCss ) {
327
+ return new Response ( html , responseInit ) ;
328
+ }
328
329
329
- if ( renderMode === RenderMode . Server ) {
330
- // Only cache if we are running in SSR Mode.
331
- const cacheKey = await sha256 ( html ) ;
332
- let htmlWithCriticalCss = this . criticalCssLRUCache . get ( cacheKey ) ;
333
- if ( htmlWithCriticalCss === undefined ) {
334
- htmlWithCriticalCss = await this . inlineCriticalCssProcessor . process ( html ) ;
335
- this . criticalCssLRUCache . put ( cacheKey , htmlWithCriticalCss ) ;
330
+ this . inlineCriticalCssProcessor ??= new InlineCriticalCssProcessor ( ( path : string ) => {
331
+ const fileName = path . split ( '/' ) . pop ( ) ?? path ;
332
+
333
+ return this . assets . getServerAsset ( fileName ) . text ( ) ;
334
+ } ) ;
335
+
336
+ const { inlineCriticalCssProcessor, criticalCssLRUCache, textDecoder } = this ;
337
+
338
+ // Use a stream to send the response before inlining critical CSS, improving performance via header flushing.
339
+ const stream = new ReadableStream ( {
340
+ async start ( controller ) {
341
+ let htmlWithCriticalCss ;
342
+
343
+ try {
344
+ if ( renderMode === RenderMode . Server ) {
345
+ const cacheKey = await sha256 ( html ) ;
346
+ htmlWithCriticalCss = criticalCssLRUCache . get ( cacheKey ) ;
347
+ if ( ! htmlWithCriticalCss ) {
348
+ htmlWithCriticalCss = await inlineCriticalCssProcessor . process ( html ) ;
349
+ criticalCssLRUCache . put ( cacheKey , htmlWithCriticalCss ) ;
350
+ }
351
+ } else {
352
+ htmlWithCriticalCss = await inlineCriticalCssProcessor . process ( html ) ;
353
+ }
354
+ } catch ( error ) {
355
+ // eslint-disable-next-line no-console
356
+ console . error ( `An error occurred while inlining critical CSS for: ${ url } .` , error ) ;
336
357
}
337
358
338
- html = htmlWithCriticalCss ;
339
- } else {
340
- html = await this . inlineCriticalCssProcessor . process ( html ) ;
341
- }
342
- }
359
+ controller . enqueue ( textDecoder . encode ( htmlWithCriticalCss ?? html ) ) ;
360
+
361
+ controller . close ( ) ;
362
+ } ,
363
+ } ) ;
343
364
344
- return new Response ( html , responseInit ) ;
365
+ return new Response ( stream , responseInit ) ;
345
366
}
346
367
347
368
/**
0 commit comments