Boost NextJS TTI & FID performance without compromise and pain

Why should you read this blog?

  • As the title said: “Boost NextJS TTI & FID performance without compromise and pain”
  • Islands Architectures for Nextjs


Hydrating is PURE OVERHEAD

As described in the post above, Hydration progress is PURE OVERHEAD since you need to load the code and render the component twice.
Imagine you have a very long landing page built by Nextjs and most of it is a static component, then when you hit the Enter in the URL:
  1. HTML contains all your landing page content sent to the browser (Which is the result of SSR)
  1. JavaScript is downloaded to the browser, get parsed, and executed (Most of it contains text content only which is nearly the same as your HTML)
  1. Which Javascript downloaded, now it attaches events to the DOM. Now your website is fully usable
The second moves make most of SSR page has TTI (Time To Interactive) and FID (First Input Delay) so high

Progressive Hydration

Let’s take a step to optimize our long-landing-page. Because on our landing page, most of the component is static (Only text and image, nothing much called “interactive”) so it’s a waste of time to hydrate those components. What if we disable hydrate for some components or only hydrate components when it’s in the Viewport
notion image
This can easily archive using react-hydration-on-demand
import withHydrationOnDemand from "react-hydration-on-demand"; import Card from "../Card"; // Hydrate when the component enters the viewport const CardWithHydrationOnDemand = withHydrationOnDemand({ on: ["visible"] })( Card ); export default class App extends React.Component { render() { return ( <CardWithHydrationOnDemand title="my card" wrapperProps={{ className: "customClassName", style: { display: "contents" }, }} /> ); } }
Now you can optimize the 3rd bullet - Reduce the time JavaScript executed to hydrate our landing page. Good job!

Lazy load component code and hydrate when needed

We can save some executed time using react-hydration-on-demand but we still have lots of redundancy code here.
JavaScript of those components is still downloaded and parsed, it just doesn’t get executed. Do we have any way to fully render the HTML of the website but only load the component’s JS only when needed?
notion image
The idea is quite simple:
  • Fully render HTML in SSR
  • Load a really minimum of JavaScript to listen to the events
  • If an event is fired, load the JS related to it and executed
This solution comes with a huge performance boost by scarifying a little time between every user’s interactive. But I do think it worse doing so 🌟
Disable Javascript reduces the TTI more than 7 times. What if we can remove half of it?
Disable Javascript reduces the TTI more than 7 times. What if we can remove half of it?
This is nice! The solution is simple but quite hard to do. Why?
  • In Nextjs, if the component is defined as dynamic and it renders in SSR, its JS also gets sent to the browser right away so nothing called lazy here
Read more
So I make a package that can
  • Skip the component hydrating process. Heavily based on react-hydration-on-demand
  • Remove the JS from the bundle and make you control when the JS is loaded
How can I do this trick? Check it out
Here is the result

How to use it

npm install next-lazy-hydrate yarn add next-lazy-hydrate
import lazyHydrate from 'next-lazy-hydrate'; // Static component const WhyUs = lazyHydrate(() => import('../components/whyus')); // Lazy hydrate when users hover the component const Footer = lazyHydrate( () => import('../components/footer', { on: ['hover'] }) ); const HomePage = () => { return ( <div> <AboveTheFoldComponent /> {/* ----The Fold---- */} <WhyUs /> <Footer /> </div> ); };
thanhlmmUpdated Mar 29, 2023
The API is quite simple, I’d love to see how this package can help you Boost NextJS TTI & FID performance without compromise and pain

Loading Comments...

Follow me @thanhledev

Xin lỗi các bạn vì thời gian qua mình không dành thời gian viết nhiều. Dạo này mình khá bận cho dự án Check it out 🥳