When we build a web app, we continually test its performance systematically and objectively against the industry standard auditing tool — Google Lighthouse (available in Chrome’s inspector).
These audits measure a range of factors by loading a page and throttling down resources to compute a score out of 100. A 100/100 score represents best-in-class performance and is incredibly difficult to achieve, but a goal we aim for with all our projects.
Here's a few things we consider when addressing performance...
Optimising for first load
One of the first things a user notices in how long an app takes to load. There are two parts to this: time to first render and time to interactive (TTI). The biggest factors impacting first render and TTI is:
- the number of render-blocking processes that have to complete before a page loads.
You can also follow an "app shell" model for UIs, prioritising the render of your basic layout before loading in components, will improve first render and users’ perception of performance. You can pair this idea with animated grey blocks, also called a Skeleton state.
You can also set up code splitting by route to further reduce code weight, only loading the code required for any one page when it is viewed. Additionally, you can lazy-load heavy assets like web fonts, swapping them in once a page has loaded, rather than blocking render.
Using the metal
Wherever possible, you should aim to leverage the web platform for a given feature. This will both allow you to reduce code weight and have native-like performance under the hood.
Using new web standards, and polyfilling for legacy browsers (CSS Variables, CSS Grid, etc) Balancing developer productivity with web standard, by avoiding patterns like CSS-in-JS that are nice for developers but negatively impact performance
Progressive Web Apps
New browser APIs allow you to prepare your app as a Progressive Web App that is offline-capable, installable on mobile devices, and highly performant. You can build service workers (or more likely, use a plugin like next-pwa) to intelligently cache content and harden your app against patchy network connectivity.
Additionally, you can look into prefetching, preloading, and preconnecting to critical resources, as well as setting up a solid manifest to make your web app installable on mobile devices.
If you choose to develop a decoupled web app (a static frontend that consumes an API), you can easily take advantage of blazing fast infrastructure. We use tools like Firebase a lot for this type of setup.
Hosting on the right platform can also help — choosing a host with a global static-file CDN like Netlify or Vercel can speed up content delivery. If you can manage it, serving all assets over HTTP/2 can allow for simultaneous connections that vastly improve network performance.
Lastly, consider aggressively cache long-term static assets and using HTTP/2 Push to preemptively serve critical resources, before your app even requests them.