-
Notifications
You must be signed in to change notification settings - Fork 482
inlineCriticalCss is slow #2106
Comments
Hi @amakhrov, Thanks for trying the feedback. I'll pass this to the Chrome SDK team since they are responsible of |
@janicklas-ralph kindly see above. |
Thank you very much @alan-agius4 I will watch this issue from now on. :) |
Just sharing my case, not just slow, it use the CPU more than 100% and server goes down and it was really critical. |
I did existing tools research and wanted to share some thoughts here. However, PurgeCSS (https://github.com/FullHuman/purgecss) uses a different approach: it extracts all class names, tag names, ids and attributes from html, stores them in sets. And then checks whether all parts of a particular css selector are included in those sets. Since set lookup is constant, it gives a solid CPU boost. The tradeoff is that the result is less precise: some complex CSS rules are incorrectly marked as "used", while they do not match the actual DOM tree shape. Critters makes a lot of sense with pre-rendering. However, SSR suffers a lot from its CPU-bound computations. Maybe we could use different tools for those two use cases? Less precise but faster - for SSR. And more precise but slower for pre-rendering. |
Even disabling inlineCritical in angular.json do not solve this problem
also in server block
How can inlineCritical be disabled and not affecting SSR and CPU utilization?
|
You need to disable it in your |
Thanks @alan-agius4 this actually helped in server.ts
|
Thank you @alan-agius4 & @ubaidazad. 💯 👍 Temporarily disabling the feature in At FloSports, we have a content-rich web app and several news articles with chunky HTML tables (~150KB) of athlete/team data (imagine an Excel dumps worth). Those articles really magnified the speed issue with +20s renders. In addition to these articles, in general, we saw an increase in SSR latency of 2.1x to 3.2x across all of our pages. We didn't notice the issue until it deployed to production. Below you can see when we were alerted via Datadog of an anomaly and debugged a bit before manually rolling back the deployment. |
@peturh, by downgrading you will be disabling critical css inlining. It is also unclear which version you are using, there were some changes in critters recently and are available in v13+ and the latest patch version of v12, which is 12.1.3. |
We've used: Angular
|
That cannot be right, because |
Sorry, updated my post with my current package.json |
So after doing this correctly and using correct packages, I still suffer a lot in response time on the server. With the setting Update:
Update 2: Followed @alan-agius4 example and added:
to |
If you disable See : https://angular.io/guide/workspace-config#optimization-configuration. |
I have been working on improving the lighthouse score in one my sites and I upgraded to Angular 13 recently. I read this thread and removing |
@CarlosTorrecillas Hi, Did you face any flicker issues in Angular 13? I meant the bootstrap loading delayed for the first-page load. On first page load the UI was broken then back to normal fraction of seconds |
As long as the HTML generated by SSR is identical to the client HTML there should be no flickering - or at least I don't experience it. Try refreshing the app with JavaScript disabled and observe what's wrong with the HTML. What I do experience is scrollbar jumping like there's no tomorrow, when you refresh the page with scrollbar not at the top - it jumps to top on refresh and back to original position when angular bootstraps. However the HTML is not broken. |
@poonga in my case I did have very little flickering. Still present but sometimes you don't even notice. For me the issue was the lighthouse ranking in the page speed score for Google which was improved |
@CarlosTorrecillas Could you please suggest some tips to address those feedbacks? |
Hi @poonga , Without looking at the code / setup, I would recommend several checks to try mitigating the errors / bad score here:
Hope this helps. This is my two cents based on my experience with Angular SSR. |
This comment was marked as spam.
This comment was marked as spam.
@CarlosTorrecillas how did this not cause your site to flicker as the browser waits for your CSS file to be loaded? Also, does anyone know if inlineCriticalCSS is defaulted to true or false? |
@alan-agius4 do you think after we upgrade to |
@CarlosTorrecillas, there are no further performance improvements planned for critical CSS inlining at the moment. |
OK, would you be able to confirm whether reverting back to "inlineCriticalCss: true" is, as performant (or even more performant) than the current workaround where we had to disable that optimisation on both the browser and the server? Essentially I want to know if it is safe for us to put back that setting or not. Not sure if you guys had any kind of benchmark around that area that can throw out some numbers to reflect it? Thanks! |
Enabling That said, this should only effect the first request for every given page if the response is being cached at a CDN/server cache layer. Caching is highly advised regardless of enabling inline critical CSS or not. Overall, I recommend to benchmark your application and would appreciate if you could share some numbers with us. |
@alan-agius4, I think I can have a baseline for the last 90 days because I can access the Google Search Console report for the crawling stats. Assuming this can be accepted as a valid benchmark I can see the impact of having the flag turned ON in April where the AVG response time went over 400ms peeking 470 and I disabled ( In my case, the static content gets cached in the browser via headers and the dynamic content that gets generated by APIs is automatically cached on the server. At the moment I can see response times that to me are "OK / GOOD" - 270ms aprox. since last week or so when I re-disabled the flag. I plan to upgrade to Angular I can share with you, at least, the graph I just collected from Google Search Console about my site where you can clearly see the performance hit during the past two months or so when I put |
Hi @alan-agius4 , do you know whether standalone components and a possible migration from modules to standalone application could also impact negatively in the performance of the application? I migrated my entire application to standalone and couldn't see major improvements. In fact I saw a slightly decrease in performance - not sure if that could be related because we are currently making several changes to the application to try to optimize specially the initial bootstrap time. We still have |
Hi @CarlosTorrecillas @alan-agius4 Currently we have inlineCriticalCss: false and "optimization": true in angular.json I have read also about purgeCss. Should we implement purgeCss? if we set "styles": { "minify": true, "inlineCritical": false } Thanks |
Hi @Juanico18 , According to what has been said in this thread, some research I have performed about this topic and the results I got, you should modify BOTH the
my
then the
With that and having reviewed my app in terms of component load and migrated to standalone components I do have better response times according to the Google Crawler (@alan-agius4 this can be interesting to you as well because it is the continuation of the graph I showed a while ago after disabling inlineCriticalCss and also after upgrading to Angular 16 and migrating to standalone components) I also have an active post in StackOverflow regarding possible optimizations of the main bundle to try to reduc/optimize it and get better Google PageSpeed results - https://stackoverflow.com/questions/76730455/reduce-main-js-file-in-angular Finally, about |
Thanks for the info. I have correct configuration. By mistake I checked wrong the angular.json file server.engine('html', ngExpressEngine({ Some more questions: Have you already mirgrated to angular16? Is purgeCss compatible with minify done by the angular cli bulid? Thanks |
Hello @Juanico18 , I have migrated to PurgeCSS is compatible. You can apply it as part of the process. The "only" test I have to conduct now is to revert back to Regards |
Hi @alan-agius4 , I rolled out an upgrade of the website including the latest I'm sharing now the results about the before (
Note that I have the latest version of the framework - In my opinion, for the time being I think that feature should be defaulted to false to get the best performance until we have a version that offers better results. |
@CarlosTorrecillas, would you be able to provide a repro please? Unfortunately without a reproduction it's hard to tell why the CLS increased. Are you getting some errors or warnings on the server during the request? |
Hi @alan-agius4 , I am not able to provide a repro unfortunately. I know it is complicated for you to know why this happens. For me is also difficult as I cannot upload a site to make the lighthouse target it in order to provide results. If I share the results form my local environment running locally the lighthouse I get different results - the site is very performant. In terms of errors, I get none. It is simply that the performance gets worse. |
you can invite him if you can, mostly the criticalCss fail because your API call not fast enough or some async function. I have no issue with that. You should solve this by check api call on platformBrowser and split the job between server render and client |
@CarlosTorrecillas, at the very minimum can you provide a CPU profile? |
Hi @alan-agius4 , If what you mean is the performance monitor that Chrome DevTools provide, I can provide the following screenshot that has the spike when the app loads then it lasts a short while and resource consumption goes back down again. I have seen the CPU going from 0 to 32-40% on my laptop (12th Gen Intel(R) Core(TM) i7-1270P 2.20 GHz) but on my mobile the app also loads pretty fast (iPhone XS). I have two performance profiles (one in dev mode, running locally and one in prod which I can share with you over email if you provide me one - if that is of any use. Now, looking back at the results I provided from the Lighthouse, I saw something interesting which maybe impacting the overall load time which again, may or may not be related to the CLS issue - I think it is worth checking it because it could have a side effect: I was running DEV:SSR locally and, with CACHE DISABLED I paid close attention to the JS files that were loaded. I could clearly see the list of dependencies that are loaded which perfectly match all the standalone components I have on the route to be rendered: Then I looked at the Lighthouse results which was telling me that I could reduce the unused JS. That, I thought could have an impact in the performance hence it could also impact somehow in the CLS score. So I opened the PROD version of the page (https://www.micarburante.com/gasolineras-en-granada/granada/shell-avenida-del-conocimiento-1-12355 - in order to perform the same test, please do not accept the cookies because other components are loaded once you have accepted them. The safest is to open in Incognito window) and looked at all the JS files beign loaded: Then I matched them all against the chunks that were produced by Angular when running And there were two things that I could not understand. If you take a look, the chunks I am sure I have no dependencies to those modules and I searched for them in the code that could cause Angular to pull the modules: So to me it seems that the final PROD bundle, somehow, is including JS from other pages and it shouldn't. Note that I have FontAwesome installed and I think that is also causing us a performance hit from what we have investigated, but in any case we are applying many strategies to get the best performance possible: using OnPush change detection where possible (and reviewed change detection cycles using Angular Profiler), using interesection observers to hide elements under the fold, using track-by functions, removing the unused CSS using PurgeCSS...My believe is that somehow the FontAwesome code is being spread across those modules and therefore they get referenced instead of having a separate chunk just for that. We are using a few icons here and there and for now we are referencing the module in the standalone component in question and import the icon using deep paths so that the minimum code gets referenced - as suggested by FA. Finally, to give a bit more visibility about the infrastructure, the set up is a full standalone component SSR solution, running on a I have deployed a new version of the site with Also we considered looking at this dependency mistery, what I can say, and there is no doubt about it, is that at the very moment I enable inlineCriticalCss the overall performance of the application gets reduced and I also have a worse CLS score. That happens toggling that flag instantly in the Lighthouse score so there is definitely something ELSE that is ALSO going on that is affecting it. I'm happy to discuss that further on a call if needed |
Hi @CarlosTorrecillas, thanks for the detailed information but it feels like we are diverging from the original issue which is that critical css inlining is slow, which needs to be benchmarked and profiled on the server. I did mean a CPU profile (of the server) which can be captured by Chrome devtools. There is a good explanation angular/angular-cli#8259 (comment) on how to capture this, although in your case you need to replace This CPU profile is needed to see part of the code is the bottleneck of critical css inlining which does not happen on the browser. To why CLS has deteriorated with critical css inlining, is completely unrelated to this issue, but again without a minimal reproduction it's hard to tell what is happening. Although I did notice that some elements like Overall, I think your issue is completely unrelated to issue reported here, which is about critical css inlining is slow on the server. |
OK cool, I am able to get the debugger attached but in my case, as we want to debug the server I am doing:
because we want to debug the server. Then I get the debugger attached and it breaks at the very top line of the first file and I hit play so that I get the node server running. After that I am not able to see the Profilter tab in Chrome DevTools. I only see a Performance tab which seems to be capturing only Memory but not CPU. Any ideas? |
@alan-agius4 , I have managed to run a node CPU profiler using another command so I can share some results and hopefully they can be of some use. SETTING INLINE CRITICAL CSS TO TRUE `Statistical profiling result from isolate-000001F0AEA656E0-4000-v8.log, (574 ticks, 0 unaccounted, 0 excluded). [Shared libraries]: [JavaScript]: [C++]: [Summary]: [C++ entry points]: [Bottom up (heavy) profile]: ticks parent name SETTING INLINE CRITICAL CSS TO FALSE `Statistical profiling result from isolate-000002C4FD1A5E40-29108-v8.log, (696 ticks, 0 unaccounted, 0 excluded). [Shared libraries]: [JavaScript]: [C++]: [Summary]: [C++ entry points]: [Bottom up (heavy) profile]: ticks parent name
` |
The performance tab captures CPO profile by default as far as I recall. I am not quite sure on how can I interprit the above sent profiles as there is no timing information. |
@alan-agius4 , I have tried again and did a "Performance" recording. INLINE CRITICAL CSS FALSE INLINE CRITICAL CSS TRUE I have both profile files which I can send if needed via email. Let me know if that is of any use. |
Please do send them via email or you can zip them and upload them here. |
There you go. |
Thanks for the profiles. I checked the profiles and critical css inlining is actually pretty fast in your case considering the large amount of nodes the DOM has. In total it takes around 78ms to perform the CSS inlining. It starts at around 1580ms in the profile. Summary
The increase in CWV, (Which again is not related to this issue), is likely due some styles not being properly extracted. There can be multiple reasons for this, the main once being;
Finding the cause of an Increased CLS, should be straight forward in this case with Chrome devtools. If indeed you find that the root cause is a bug please file a new issue with a minimal reproduction Closing as it does not seem that we had further reports that critical css inlining is slow. If you do encounter an issue were critical css inlining process is slow, please file a new issue with a minimal reproduction or at the very least a CPU profile of the server during request handling. |
if so, it will be better if critters of chromelabs have some warning or notice about this. anyway, I have inlineCriticalCss work as expect without problem. Mostly project fail on this because it have issue on DOM or CSS extract, I can confirm that |
Thanks for the feedback. Definitely will look at that. I only wonder how do you guys know the CSS extractor has a bug? How can you see that? Are you talking about the actual PurgeCSS itself? If so, do you recommend another extractor that won’t have that issue? in terms of the CLS process and overall CWV I won’t be loading in the browser the components to see the difference…I will to run the DevTools to see the CLS problem yet I could not see previously by looking at the timeline/charts with the code run… |
mostly, css death because component render process is delay, check your settimeout + observable, document.[anything] which cause the system try to render and... hanging. Yes hard to debug, use binary check. Turn off half off your module. Then test, then test the half other, one by one. |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
🐞 Bug report
What modules are related to this issue?
Is this a regression?
No
Description
Recently I tried to enable inlineCriticalCss on our project. And had to roll it back quickly - SSR times jumped sky high.
styles.css
in our project is around 250KB. This includes Angular Material (core + theme) and a number of old-style components that have not been converted tostyleUrls
yet. However even if I strip it down to bare minumum - it's still ~100KB (majority of that are Material styles).HTML is also somewhat significant - 200KB (after I stripped it off of transfered state), and contain 1500 DOM nodes.
Profiling shows that most of the css inlining time is spent on
findOne
call.My understanding is that
critters
has complexity roughlyO(N * S)
, where N is number of DOM nodes, and S is number of selectors in the stylesheets. That's because it queries every selector against the DOM. And our stylesheet (the minimal version) has 1000+ selectors. The regular prod version of the stylesheet - 2600 selectors.I'm wondering if it could be improved by grouping selectors and discarding a whole group if the top-most selector was not found. E.g if we checked
.mat-button
selector and didn't find any matching node - there is no point in looking for more specific selectors like.mat-button .mat-button-focus-overlay
🔬 Minimal Reproduction
🌍 Your Environment
The text was updated successfully, but these errors were encountered: