perf(angular): fix CLS regression from critical-CSS inlining + drop rxjs from the bundle - #34
Merged
Merged
Conversation
Angular was the only app of 15 that pulled the four shared design-system
stylesheets through angular.json's `styles` array, emitting them as a
bundled styles-<hash>.css. Every other framework (react, vue, svelte,
preact, solid, lit, qwik, astro, alpine, jquery, vanilla, vanjs, lume-js,
geajs) links them from index.html as /styles/*.css.
That inconsistency had two effects:
- the benchmark's bundle-size analysis excludes shared assets by name
and by directory, so the other 14 apps never get these bytes counted
while Angular did -- 17.4 kB raw / 3.79 kB gzipped of pure penalty
- Angular served one minified bundle where everyone else serves four
unminified files, so the Lighthouse comparison was not like-for-like
either
Aligning Angular with the other 14 makes both measurements comparable.
Counted bundle (same method as scripts/benchmark/bundle_size.py):
before 176,043 raw / 55,224 gzipped
after 158,642 raw / 51,430 gzipped
react 158,538 raw / 50,256 gzipped (published 2025-09-09)
Lighthouse is unchanged at performance 100 / a11y 100 / best-practices 100,
CLS 0, verified over two runs.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lissy93
approved these changes
Aug 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two independent optimisations to the Angular app:
rxResourcetoresource().1. CLS: disable
inlineCriticalAngular's critical-CSS inlining (beasties) runs against the built
index.html, where<app-root>is still empty. It therefore only finds:root/html/bodyrules toinline, and defers the real stylesheet:
The app paints unstyled, then the stylesheet arrives and re-lays out the whole page.
Lighthouse attributes a 0.724 layout shift to
<main class="main">.Since nothing renders before the JS bootstrap anyway, making the stylesheet render-blocking
costs nothing on FCP/LCP and removes the shift entirely.
Accessibility and best-practices stay at 100.
2. Drop rxjs from the bundle
resource()is stable public API in Angular 22 (@publicApi 22.0) and takes a promiseloader, so
@angular/core/rxjs-interopand the rxjs operators are no longer reachable:weather-state.service.ts:rxResource({ stream })toresource({ loader })weather.service.ts: Observables toasync/awaitover the existingfetchcallsrxjsstays inpackage.jsonit is still a required peer dependency of@angular/corebut its operators no longer end up in the output.Bonus: the loader now forwards
resource()'sabortSignaldown tofetch, so switchingcity actually cancels the in-flight request instead of letting it race.
eslint.config.mjsgainsAbortSignal: 'readonly'alongside the other browser globals.