How to improve performance of Next.js website?
Sumukhakb
Posted on June 26, 2022
In this post, I'll teach you how to boost the performance of your Next.js website. I'm going to utilize the Lighthouse Chrome add-on to measure performance (now by default it is available). There may also be some simple tips included. Depending upon the type of website, always make sure your score is more than 80. I utilized some methods listed below to improve the performance of my website.
Repo(This is my personal portfolio website) :- https://github.com/Sumukha210/new-portfolio-website
1) Always use Lighthouse in private mode.
It is a basic strategy, but it is incredibly successful. Because when you run your lighthouse, the performance may suffer owing to external interference such as chrome extensions, scripts, and so on. Also, be certain that you are running a production build. To run the production build, use yarn run build
.
2) Lazy loading.
I utilized a smoke effect on my website by copying and pasting the codepen demo https://codepen.io/Irehan/pen/YgyozL. It works great on the desktop, however it does not operate properly on touch devices. Also, because it uses WebGL, there is a lot of code; to avoid this, I lazily loaded the code. Similar to this
const lazyLoadSmokeEffect = async (canvas: any) => {
const { smokeSimulation } = await import("./SmokeEffect");
smokeSimulation(canvas); // This functions contains the code
};
useIsomorphicLayoutEffect(() => {
if (canvasRef?.current && window.innerWidth >= 1200) {
setTimeout(() => {
lazyLoadSmokeEffect(canvasRef.current);
}, 2000);
}
}, []);
3) Intersection observer to lazily load the Component.
Because my site has a contact form, I used reCAPTCHA to avoid spam (check my article on how to implement Google reCAPTCHA here: https://dev.to/sumukhakb210/integrating-recaptcha-with-nextjs-4ig6), but when I checked the lighthouse tab, it generated scripts that weighed about 143kb. As a result, I employed Next.js Dynamic imports. I also used the useOnScreen custom react hook, which loads the component lazily when the user scrolls to a specific point.
Here, I implemented the Next.js Dynamic imports for contact section.
import React, { useRef } from "react";
import About from "@/modules/about/About";
import Hero from "@/modules/hero/Hero";
import Layout from "@/modules/Layout";
import Skills from "@/modules/skills/Skills";
import dynamic from "next/dynamic";
import { useOnScreen } from "@/utils/useOnScreen";
import SEO from "@/utils/SEO";
import Project from "@/modules/projects/Project";
const DynamicContactUsComponent = dynamic(
() => import("@/modules/contact/Contact"),
{
loading: () => (
<p className="loadingText subtitle-4">
Contact us Loading, please wait...
</p>
),
}
);
const MainPage = () => {
const bodyHeight = 800;
const ContactRef = useRef(null);
const isContactIntersecting = useOnScreen(ContactRef, `${bodyHeight / 2}px`);
return (
<Layout>
<SEO />
<Hero />
<About />
<Skills />
<Project />
<div ref={ContactRef} id="contactSection">
{isContactIntersecting && <DynamicContactUsComponent />}
</div>
</Layout>
);
};
export default MainPage;
useOnScreen Custom Hook,
import { MutableRefObject, useState } from "react";
import useIsomorphicLayoutEffect from "./useIsomorphicEffect";
export const useOnScreen = (
ref: MutableRefObject<null>,
rootMargin: string = "0px"
): boolean => {
const [isIntersecting, setIntersecting] = useState<boolean>(false);
useIsomorphicLayoutEffect(() => {
const observer = new IntersectionObserver(entries => {
console.log("entries", entries);
entries.forEach(
entry => {
if (entry.isIntersecting) {
setIntersecting(true);
}
},
{ rootMargin }
);
});
if (ref.current) {
observer.observe(ref.current);
}
return () => {
ref.current && observer.unobserve(ref.current);
};
}, []);
return isIntersecting;
};
Also, don't overdo it because using dynamic for more components increases the amount of requests browser sent to the server.
4) Using the Babel plugin for styled components to reduce delays while applying styles.
In .babelrc
file,
{
"presets": [
"next/babel"
],
"plugins": [
[
"styled-components"
]
]
}
In _document.tsx
import Document, { DocumentContext, DocumentInitialProps } from "next/document";
import { ServerStyleSheet } from "styled-components";
export default class MyDocument extends Document {
static async getInitialProps(
ctx: DocumentContext
): Promise<DocumentInitialProps> {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: [
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>,
],
};
} finally {
sheet.seal();
}
}
}
These are some quick tips to help you enhance your performance:-
- To display images, use the next/image component.
- Using the font optimization technique of Next.js
// pages/_document.js
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
render() {
return (
<Html>
<Head>
<link
href="https://fonts.googleapis.com/css2?family=Inter&display=optional"
rel="stylesheet"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
Thank you for reading my article. If you have any techniques for improving performance, please feel free to share them in the comments. ✌🖐👍
Posted on June 26, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.