How to improve performance of Next.js website?

sumukhakb210

Sumukhakb

Posted on June 26, 2022

How to improve performance of Next.js website?

Website speed

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.

private mode Image

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.

Smoke effect
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);
    }
  }, []);
Enter fullscreen mode Exit fullscreen mode

3) Intersection observer to lazily load the Component.

Lazy load image
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;
Enter fullscreen mode Exit fullscreen mode

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;
};
Enter fullscreen mode Exit fullscreen mode

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"
        ]
    ]
}
Enter fullscreen mode Exit fullscreen mode

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();
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Thank you for reading my article. If you have any techniques for improving performance, please feel free to share them in the comments. ✌🖐👍

💖 💪 🙅 🚩
sumukhakb210
Sumukhakb

Posted on June 26, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related