I have an Angular 16
application which uses the progressive web app
(PWA) feature and server-side rendering
. We also updated the majority of our components to standalone and lazy loaded our modules.
Since Google changed its indexing rules recently, we've been struggling to improve our FCP/LCP.
Is there any way to minify, compress and remove unused JS and CSS files on build to ensure PWA compatibility and achieve better FCP/LCP notation?
Your question is quite too complex to be easily answered. There are so many variables impacting load performance of an application. But i'll try to give you a quick overview.
Technically not Angular, but the used bundler can remove unsued code. If you build it with Angular CLI) it's doing that by default, if you're doing a production build. That functionality is called Tree Shaking and both webpack and esbuild are doing it.
Tree shaking is a term commonly used in the JavaScript context for dead-code elimination.
However, how good Tree Shaking works heavily depends on how your code is structured and which libraries you're using.
Just to name some common mistakes:
styles.css
. => Try to keep your styles local in the component that really need it.Best way to check your bundle size with a bundle analyzer and check what could be removed to optimize the bundle size.
Just as a reference, the minified Estimated transfer size
for Initial chunk files
can even for extremely complex applications be around 160-180kb. You can check the output of the Angular CLI) build for your current values. However, there will be most likely additional chunks required to show the LCP of your page.
Again it's the bundler who is responsible for minification. For Angular CLI) you can configure it in the "Optimization configuration" in the "Angular workspace configuration".
The optimization option can be either a Boolean or an Object for more fine-tune configuration. This option enables various optimizations of the build output, including:
Minification of scripts and styles
Tree-shaking
Dead-code elimination
Inlining of critical CSS
Fonts inlining
Compression is neither in the responsibility of Angular nor of the bundler. However, usually your CDN can dynamically compress your source files before delivering it. To get higher compression ratio it's a good idea to create statically precompressed brotli files. While most, but not all clients support brotli, be sure to deliver the precompressed files only to clients that support it.
server-side rendering (SSR)
and proper caching your FCP and LCP should not be a problem anyways, because LCP usually can be shown even before your application loaded the JS code. However, Interaction to Next Paint (INP) might be more problematic with SSR, because users might try to interact with the page while it's still hydrating.Deferrable views can be used in component template to defer the loading of select dependencies within that template.
However, be aware that Deferrable Views are not rendered in SSR, so it can be problematic for SEO relevant content.
When rendering an application on the server (either using SSR or SSG), defer blocks always render their @placeholder (or nothing if a placeholder is not specified). Triggers are ignored on the server.
Update 03. April 2024: Since performance optimizations is a very wide field here are some specific actions that can be taken based on the example "app.gudule.co", which was the reason the question was raised. Those suggestions are based on the current state of the application on 03. April 2024. I think it's a good addition to the generic answer above, because others might face similar issues and examples are more simple to understand. However, these are just a few first simple steps, there are a lot more possibilities, but hope it's enough to get proper performance.
server.ts
after rendering the page and before delivering it.Let's estimate what effect 2., 4. and 6. would have on LCP.
So before it's looking for a desktop like:
It's taking in that specific test 2.1s for FCP and LCP.
Let's assume suggestion 2 is done and your server is responding in 70ms with the cache. That would reduce the overall LCP by 135ms (that are currently used to render the page).
If global CSS (suggestion 4) is reduced by 50% it would save another 500ms.
Finally 6. setting the angular js files to defer would remove the requirement for them to be loaded to show the FCP and LCP. Since the images are either to small or for most users below the fold, they should have no effect on the LCP.
Overall with those improvements alone I would expect the LCP for such a synthetic test (desktop with slow DSL connection) to be reduced to around 1,2 seconds.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With