Today I took a look at Page Speed Insights, to check the performance of the website, and long story short: I needed to improve it.
On desktop devices, I got a score of 97, but it was 49 on mobile devices:
Here is the data:
Parameter | Value |
---|---|
First Contentful Paint | 6.1 s |
Speed Index | 6.1 s |
Largest Contentful Paint: | 7.5 s |
Time to interactive | 6.3 s |
Total Blocking Time | 210 ms |
Cumulative Layout Shift | 0 |
I wanted to improve the First Contentful Paint parameter, which is the time when the browser renders the first bit of content.
This is one of the keys parameters to improve, since attention spans are low these days, and users haven't much patience. Google estimates that the ideal range of this parameter is between 0 and 2 seconds.
At first, I've thought that the main page had a problem with a chunk of JavaScript, so I tried to simplify it by removing some functions and refactoring the component.
Then, I relaunched the test and I saw a 9 points improvement:
Here is the data:
Parameter | Value |
---|---|
First Contentful Paint | 3.9 s |
Speed Index | 4.3 s |
Largest Contentful Paint: | 6.1 s |
Time to interactive | 4.7 s |
Total Blocking Time | 440 ms |
Cumulative Layout Shift | 0 |
If you are developing with React and create-react-app
, you can see that after building your application, Webpack bundles JavaScript into a chunk (same with CSS). To improve website performance, it's recommended to divide the JavaScript into smaller chunks.
React API has a function called lazy
and a component called Suspense
. When Webpack detects a lazy component, it will be loaded after the non-lazy ones.
So, for example, let's say that you have the following app:
jsximport React from 'react'; import Nav from './Nav'; import Content from './Content'; import Footer from './Footer'; const App = () => { return( <> <Nav/> <Content/> <Footer/> </> ); } export default App;
After running npm run build
, React will create a file such as main.chunk.js
. Depending on the size of <Nav/>
, <Content/>
and <Footer/>
, the file can be heavy.
In this example, the three components will load at once.
Imagine that <Nav/>
and <Footer/>
are light components; if you display them before the content is loaded, the user experience will improve (the user wants to see something on the screen as soon as possible).
jsximport React, { Suspense, lazy } from 'react'; import Nav from './Nav'; import Footer from './Footer'; const Content = lazy(() => import('./Content')); const App = () => { return( <> <Nav/> <Suspense fallback = {<div>Loading...</div>}> <Content/> </Suspense> <Footer/> </> ); } export default App;
At this point, <Content/>
will be suspended until it's loaded. As you can see, the <Suspense/>
component has fallback
as a prop, which is the HTML to show while the component is loading.
After building the application, you'll have small JavaScript chunks, such as 01.5664eb.chunk.js
, 02.54678eg.chunk.js
, etc.
So, now, if the user launches the application, the navigator and footer will display first, and the content a little bit later. Using lazy imports, improved the First Contentful Paint to 1.6 s and a score of 98:
Here is the data:
Parameter | Value |
---|---|
First Contentful Paint | 1.6 s |
Speed Index | 2.6 s |
Largest Contentful Paint: | 2.2 s |
Time to interactive | 1.6 s |
Total Blocking Time | 0 ms |
Cumulative Layout Shift | 0 |
Hi, I'm Erik, an engineer from Barcelona. If you like the post or have any comments, say hi.