You have unlimited access as a PRO member
You are receiving a free preview of 3 lessons
Your free preview as expired - please upgrade to PRO
Contents
Recent Posts
- Object Oriented Programming With TypeScript
- Angular Elements Advanced Techniques
- TypeScript - the Basics
- The Real State of JavaScript 2018
- Cloud Scheduler for Firebase Functions
- Testing Firestore Security Rules With the Emulator
- How to Use Git and Github
- Infinite Virtual Scroll With the Angular CDK
- Build a Group Chat With Firestore
- Async Await Pro Tips
Angular PWA Performance Optimization and Analysis
Episode 73 written by Jeff DelaneyIn this lesson, my goal is to share a handful of tips and ideas aimed at optimizing the Lighthouse PWA performance score. Any good optimization starts with a thorough analysis, so I will also provide you with some advanced tools for analyzing the performance for your progressive web app.
High Performance PWAs with Angular
PWA performance is largely dependent on the way you design your app. In this demo, I am following the PRPL pattern from Polymer as closely as possible.
- Push critical resources first via index.html.
- Render initial route with a very lean app module.
- Pre-cache remaining routes with the Service Worker.
- Lazy-load remaining routes with Angular NgModules.
The primary drivers of performance in Angular include the size of the resources and number of network calls required to render the page.
Here’s a visual breakdown of how our Angular app loads. We have an initial loading splash page, then our app module shell (first paint), then firebase loads the data and our page becomes fully interactive.
How to Analyze Bundle Sizes
The webpack bundle analyzer is a great way to see what’s taking up space in your app. Thanks Cory Rylan for a great overview of this technique.
First, build your app ng build --prod --stats-json
. This will add an extra dist/stats.json file that contains an analysis of the parts wrapped inside the bundle.
Bundle Analysis in Three Easy Steps
- Install the tool with
npm install webpack-bundle-analyzer -D
- Add a new script to your package.json file
"analyzer": "webpack-bundle-analyzer dist/stats.json"
: - Run
npm run analyzer
As you can see, Angular is a largest resource, while the Firebase SDK is a close second. I will show you how to lazy load firebase in the next step to dramatically reduce the bundle size.
Additional Analysis Tools for PWAs
In addition to Lighthouse for Chrome, you might also check out the following tools for additional benchmarking.
Web Page Test. Web Page Test gives you the most detailed loading waterfall of any other tool on the web. Hacker News uses it when ranking submissions and it can be very helpful for tracking down bottlenecks.
Website Grader by Hubspot. Although not for PWAs, it’s a useful tool to see how you stack up to regular websites with performance, security, and SEO.
Lazy Loading Dynamic Content
Ok cool, so we know our bundle size is going to impact performance, but How do you make the main bundle in Angular smaller?
I created a simple break down of lazy loaded modules here, but let’s revisit the process for our Hacker News PWA.
1. Create a Feature Module with it’s own Routes
In this case, I have a content module that will be lazy loaded.
ng g module content |
The module will handle the main views for the Hacker News app and initialize Firebase. This module accounts for about 45% of the total main bundle size. It just needs to import the router, define a few routes, then call RouterModule.forChild(routes)
in the imports section. The bare-minimum code needed for lazy loading looks like this:
import { NgModule } from '@angular/core'; |
import { NgModule } from '@angular/core'; |
2. Point the App Routing Module to the Lazy Module
The main app routing module will now lazy load the content module whenever the user navigates to a router under the /hn/
path. In this case, I am automatically redirecting, but you are not requried to do this.
import { NgModule } from '@angular/core'; |
That’s all there is to it. The content module will now be lazy loaded.
Updated Bundle Size
Our main bundle size footprint has been cut in half. The larger and more complex the app, the greater the performance gains will be from lazy loading.
The chunk.js
bundle will not be required for the initial page load.
Other Potential Optimizations
Lazy loading will deliver the largest performance gains, but there are a number of other potential optimizations worth considering.
Angular Build Optmizer
If using Angular CLI 1.5 or greater, --build-optimizer
is enabled by default.
If using Angular CLI < 1.5, run the following command and watch your bundle size magically decrease.
ng build --prod --build-optimizer |
Reducing the Impact of Render Blocking CSS
If you’re using a CSS framework, such as Bootstrap or Material, you might be faced with large render blocking stylesheets. Most CSS frameworks are build in a modular way with SASS, SCSS, or LESS. You can take advantage of these modular libraries by only importing the code you need. For example, why import the CSS code for the bootstrap carousel if your app never uses it?
- Try to minimize the footprint of your initial
styles.css
file. - Import shared styles in lazy loaded modules.
Optimize Web Fonts
If using web fonts from Google Fonts or Adobe TypeKit, it is important to minimize the included fonts to the bare minimum needed for your app. Do you really need that italic font in 300, 500, and 700 weights for the initial page load? I would hope not. Consider slimming down fonts and load less common families lazily.
Optimize Images
Large images can be a major roadblock in the critical rendering path. If you’re displaying a logo on your initial splash page, consider converting it to an Scalable Vector Graphic (SVG) rather than a PNG or JPG. In my case, this optimization cut the logo image size by over 90% from 10KB down to 750Bytes. If SVG is not practical in your case, you should still look to reduce image file sizes with one of the many compression tools available on the web.
Server Side Rendering
If you can optimize your critical rending path effectively, it is unlikely you will need SSR for performance. However, there may be some cases where Angular Universal can deliver a significant performance boost by executing your app code on a server, then responding with the fully rendered HTML. The implementation is moderately complex, so I will leave that for another video. Just keep SSR mind if you are unable to optimize your performance score with the strategies discussed in this article.
That’s all for now - let know if you have any other PWA optimization ideas in the comments.