Web Performance

2022-10-05

A fast application gives a better experience for the users. If a page takes too long to load, people will leave before they even see the content. I have spent some time optimising web performance in my projects and there are several areas that can make a noticeable difference.

Images

Images are often the largest files on a page. There are a few things we can do to reduce their impact. First, use the right format. For photos, JPEG or WebP works well. For icons and illustrations with flat colours, SVG or PNG is better. WebP generally produces smaller files than JPEG at similar quality.

Second, resize images to the dimensions they will actually be displayed at. There is no point serving a 4000px wide image if it is only displayed at 400px. Third, use lazy loading so images below the fold are only loaded when the user scrolls near them. In HTML, we can add loading="lazy" to the img tag.

Bundle Size

For JavaScript applications, the bundle size affects how long it takes for the page to become interactive. A few things that help:

Code splitting breaks the bundle into smaller chunks that are loaded on demand. In React, we can use React.lazy and Suspense to load components only when they are needed. For example, if we have an admin dashboard that only admin users see, there is no need to include that code in the initial bundle for everyone.

Tree shaking removes unused code from the bundle. Most modern bundlers do this automatically, but it only works with ES module imports. If we import a large library but only use one function from it, tree shaking will exclude the rest.

Dependency audit is also worth doing periodically. Sometimes we install a library for a small feature and forget about it. Running npm ls or using a bundle analyser tool can help identify large dependencies that we might not need anymore.

Caching

The browser can cache static files like JavaScript, CSS, and images so they do not need to be downloaded again on repeat visits. We can control this with cache headers on the server. For files that include a hash in their filename (which most build tools generate), we can set a long cache duration because the filename changes whenever the content changes.

For API responses, we can also implement caching on the client side. If the data does not change frequently, we can store it in memory or use a library that handles caching and revalidation automatically.

Rendering

How the page renders also affects perceived performance. Server-side rendering (SSR) sends fully rendered HTML to the browser, so the user sees content immediately while JavaScript is still loading. Static site generation (SSG) takes this further by generating the HTML at build time, which is even faster because there is no server processing on each request.

For pages that have dynamic content, we can use a combination: render the shell and static parts immediately, and load the dynamic parts after the page is interactive. This way the user does not stare at a blank screen while waiting for everything to load.