SHARE
39% of users will stop engaging with content when loading time takes too long.
Performance is highly important for each website. Only if your website quickly responds, is optimized, loads fast, and so on, in most cases, these will be taken for granted by users. Your designers can do incredible work and make your website sweet like candy, but if it loads slowly, believe me, the user will notice it first and leave with an unpleasant aftertaste.
Google is aware of user's preferences and therefore performance is one of the most important metrics it uses to decide which search page your site is shown on. To determine such indicators, Google has its own Lighthouse service. At the moment, the current version is v8, but some Google documentation already mentions the ninth version. While Lighthouse defines metrics like performance, accessibility, SEO, best practices, PWA, performance is where the most contentious issues arise.
The performance by itself is determined by several sub-metrics – TBT (Total blocking time), LCP (Largest contentful paint), CLS (Cumulative layout shift), TTI (Time to interactive), FCP (First contentful paint), Speed index. I’m listing them in order of performance impact. We will practically not talk about the Speed index, including Speed Index Lighthouse, since this is a very difficult metric to understand and change on the part of a programmer.
Lighthouse has two verification options: for desktop and mobile devices. During testing on mobile devices, performance metrics will always be lower. Let's be honest, we are looking for information using our phones more and more often. So you can't just ignore that fact. Your application should run fast enough on any device.
There is another metric that we have not mentioned yet, but it is extremely important. This is the time to the first bit (Time To First Byte – TTFB). TTFB measures the duration between an HTTP request and the beginning of the server's response. Back-end specialists have more opportunities to influence it. However, frontenders can at least avoid requesting unnecessary data, which is especially true if you are using GraphQL.
This is the time between the first rendering of site content and the moment your application becomes fully interactive. And, no… Your application does not immediately become interactive as soon as you see its first elements. There is a short period when the main thread is blocked and does not respond to any user reactions. How long it will be blocked, entirely is up to you. Each time the main thread encounters a task that takes over 50 milliseconds, that task is automatically considered as too long and the thread is considered as blocked. Fortunately, TBT takes into account only the time greater than 50ms. So, if you have a long-lasting task that takes 53 ms, then TBT will be only 3 ms. But if there are several tasks like this, the extra execution time will be summed up.
This is the time on the scale between the first rendering of content and the so-called “quiet window” of 5 seconds. This is the 5 seconds when there are no long-lasting tasks for execution. Server rendering can cause a page to look interactive but it's not actually interactive due to blocking the main thread. Hereby, you see the button, but nothing happens when you click it. It infuriates users, as Google informs that your site is slow. It can lead to unexpected page jumps, so don't be surprised if you don't rank on the first page.
As you can see, these indicators are interconnected. Therefore, you can optimize the application for both at once.
The first thing a user sees on a page when it loads. According to Lighthouse, it can be any image, not a white <canvas>, as well as SVG elements on the page. The important thing is that everything inside the iframe is not counted. It's also text, and therefore fonts, so make sure they're displayed. Add a property font-display: swap; to your @font-face. This is the fastest way to resolve the issue.
This is the largest element in the viewport. Usually, people are used to thinking that this is an image because often the biggest element on the first screen is the cover image or image slider, but this is not always the case. For example, this is the h1 heading on our website.
LCP can be:
They all can be optimized to increase Next.js performance.
Use these best practices (as well as Next.js best practices) to improve your performance.
Have you ever visited a site, clicked on any button or product, and as a result, another element appeared on the top? And it turns out that you clicked on a completely different block or even on an advertising banner? Users do not like this and Google, accordingly, too. Block size jumps like this increase the value of the CLS factor, which is bad for performance.
The easiest way is to read carefully the Next.js documentation, which developers update periodically. There you can find out that:
This will help you improve next.js performance, too.
Next.js bundle analyzers make it easier to keep track of the bundle size, so use these several tools:
There is such an interesting feature in Next.js as shallow routing. This is one of the options you may see when using router.push or router.replace. The default is false. But if set to true, then the whole page will not be reloaded when the URL changes and getServerSideProps will not work and will not load new data again. Be careful, the rerender may not be noticeable in local development, but it will definitely show up in production. If you're using filters based on URL query parameters, it's better to track that the URL has changed and load the data in useEffect again just for the desired block.
Use SWR to load data on the client instead of useEffect. It was specially created by Next.js. It automatically caches and revalidates data, and also allows you to request data from the server at regular intervals.
There are times when you need to load different components depending on the width of the window. If you use conditional rendering and hooks like useWindowSize for this, rather than CSS styles, FCP loading may differ from the final result. In this case, the CLS will be huge, and the user will see a very jumping page at the beginning. This can be avoided if you determine which device and what sizes the user uses on the Next.js server. Package mobile-detect will help you a lot with this and will allow you to reduce CLS to zero.
To significantly improve the FCP and LCP values, and with them the rest of the indicators, you need to replace the NextScript import in the custom document _document.js/.ts. Replace it with this file, which have been posted by incredible David Zhao. This hack saved me when I was struggling with huge FCP and LCP stats for days and added about 30 points to my Lighthouse Performance score.
But we will not mindlessly copy-paste, so I will briefly tell you how it works. Remember how we usually load scripts using pure JS, HTML, CSS? We add them either in the head before the body, or at the end. Only in this case, we already have some kind of layout, the elements are mostly displayed, but interactivity is achieved through JS. So we can afford asynchronous loading of scripts after layout.
However, when we use frameworks like Next.js, we have JS that creates the entire page. That is to say, the script will always be in the head. But inside it also loads the scripts of the libraries, Next.js itself. We saw above that we can change the way some scripts are loaded using the Script component. But with internal scripts and node modules, this will not work.
By default, NextScript loads scripts onto the page using the async property. Thus, HTML is parsed first and the script is loaded. Then you have to wait until the script completes and only then continue parsing HTML.
If we use the defer property, then we get a situation where HTML is parsed first and scripts are asynchronously loaded in parallel, but we do not have to wait until they work to finish parsing HTML. Since most of the scripts are really not needed for the first render, this makes the page loading much faster.
In today's world, product's UX plays a huge role for the sucess of business as users tend to choose brands that are easthetic, fast and friendly to them. That's why any business owner should focus most part of the efforts on how improving their product's performance to make interaction experience seamless and enjoyable.
That's what we root for any product we create & encourage our partners & readers integrate in their business development strategies. Great performance is your strength, don't neglect it.