How I improved PageSpeed score with NextJS

NextJS PageSpeed
NextJS PageSpeed

Problem

I had a page with a banner image and two third-party libraries: the Remark42 (comment engine) and React Player (YouTube). As a result, the PageSpeed performance score was quite low, around 50-60. After some research, I was able to improve the score to 99-100. You can view the actual PageSpeed score here.

Solutions

The full code is at GitHub.

  1. Load the player only when the user clicks the play button

    I used a banner image with a play SVG icon to mimic a video player. When users click on it, React Player loads, and the video plays automatically.

    I used the useState to keep track of the video playing status:

    const [isPlaying, setIsPlaying] = useState(false)
    const hasVideo = blog.attributes.mediaUrl
    

    And I used Next.js Image with placeholder and blurDataURL to further optimize performance:

    {hasVideo && !isPlaying ? (
      <div className="relative aspect-video w-full overflow-hidden rounded-md bg-gray-900">
        <Image
          className="h-full w-full object-cover"
          src={blog.attributes.seo.metaImage.data.attributes.url}
          alt={blog.attributes.seo.metaImage.data.attributes.caption}
          width={blog.attributes.seo.metaImage.data.attributes.width}
          height={
            blog.attributes.seo.metaImage.data.attributes.height
          }
          priority={true}
          loading="eager"
          placeholder="blur"
          blurDataURL={BLUR_IMAGE}
        />
    
        {/* Play Button Overlay */}
        <button
          onClick={() => setIsPlaying(true)}
          className="absolute inset-0 flex items-center justify-center bg-black/50 transition hover:cursor-pointer hover:bg-black/30"
          aria-label="Play Video"
        >
          <PlayCircleIcon className="h-20 w-20 text-white drop-shadow-lg" />
        </button>
      </div>
    ) : (
      // Load ReactPlayer when user clicks play
      isPlaying && (
        <div className="player-wrapper">
          <ReactPlayer
            className="react-player"
            url={blog.attributes.mediaUrl}
            width="100%"
            height="100%"
            controls={true}
            playing={true}
            muted={false}
          />
        </div>
      )
    )}    
    
  2. Load the comment library only when necessary

    The ideal time to load Remark42 is when users scroll to the bottom of the page where the comments section is located. This prevents the script from loading when the page initially opens.

    I added a div element at the end of the page where the comments should appear and used it as a trigger to load Remark42 only when it becomes visible.

    const [showComments, setShowComments] = useState(false)
    const commentTriggerRef = useRef<HTMLDivElement | null>(null)
    
     <div ref={commentTriggerRef} className="relative">
       <div
         aria-hidden="true"
         className="absolute inset-0 flex items-center"
       >
         <div className="w-full border-t border-zinc-600" />
       </div>
     </div>   
    

    Then, I used the useEffect hook to set up an Intersection Observer, which lazily loads Remark42 when the commentTriggerRef becomes visible.

     useEffect(() => {
       const observer = new IntersectionObserver(
         (entries) => {
           if (entries[0].isIntersecting) {
             setShowComments(true)
           }
         },
         { threshold: 1.0 },
       )
    
       if (commentTriggerRef.current) {
         observer.observe(commentTriggerRef.current)
       }
    
       return () => {
         if (commentTriggerRef.current) {
           observer.unobserve(commentTriggerRef.current)
         }
       }
     }, [])   
    

    And finally, render the actual comments at the end:

    {showComments && (
      <CommentBox
        location={`${process.env.NEXT_PUBLIC_SITE_URL}/blog/${blog.attributes.slug}`}
      />
    )}    
    

Conclusion

With these simple solutions, you can significantly enhance your website's performance and improve the user experience.

PageSpeed

References