Optimize TTI và FID cho Nextjs một cách super đơn giản

Bài gốc: https://thanhle.blog/blog/optimize-tti-và-fid-cho-nextjs-mot-cach-super-don-gian Tại sao nên đọc bài này? Như tít: “Optimize TTI và FID cho Nextjs một cách super đơn giản” Islands Architectures cho Nextjs Kết quả Before https://next-lazy-hydrate-origin.vercel.app/ Live check PageSpeed After https://next-lazy-hydrate-optimized.vercel.app/ Live check PageSpeed Hydration là quá trình lãng phí tài nguyên Server side rendering với Hydration lãng phí tài nguyên

Bài gốc: https://thanhle.blog/blog/optimize-tti-và-fid-cho-nextjs-mot-cach-super-don-gian

Tại sao nên đọc bài này?

  • Như tít: “Optimize TTI và FID cho Nextjs một cách super đơn giản”
  • Islands Architectures cho Nextjs

Kết quả

Before

Untitled.png

https://next-lazy-hydrate-origin.vercel.app/

Live check PageSpeed

After

Untitled 1.png

https://next-lazy-hydrate-optimized.vercel.app/

Live check PageSpeed

Hydration là quá trình lãng phí tài nguyên

Server side rendering với Hydration lãng phí tài nguyên như thế nào?

Như bài viết trên, Hydration là quá trình khá LÃNG PHÍ TÀI NGUYÊN vì nó cần load code của component và render tới hai lần.

Tương tượng chúng ta có một trang landing page khá là dài viết bằng Nextjs, hầu hết các component đều là tĩnh (Nghĩa là chỉ render ra HTML mà không có quá nhiều Interactive). Khi chúng ta “đập” vào phím Enter trên thanh URL thì:

  1. Đống HTML của landing page được gửi xuống Browser (Là kết quả của quá trình SSR)
  2. JavaScript được download xuống Browser, phân tích, rồi thực thi (Đa số tụi nó sẽ bao gồm text và khá giống như HTML ở bước 1)
  3. Sau khi JavaScript được download, và chạy xong, nó sẽ gắn đống event cần handle vào cây DOM hiện tại. Bây giờ thì cái web của mình với có thể gọi là… load đầy đủ

Trong các bước trên, bước 2 và 3 khiến cho hai chỉ số TTI (Time To Interactive) và FID (First Input Delay) rất cao

Progressive Hydration

Xin không dịch từ trên quá tiếng Việt vì dịch ra sẽ rất chuối 🍌

Ok bây giờ thử optimize cái trang landing page dài ngoằng của chúng ta nhé. Bởi vì cái trang landing page đó hầu hết là Static Component nên hầu hết thời gian cho quá trình Hydrate Component là khá vô ích (bởi vì nó chỉ cần HTML, CSS là chạy được, méo cần JS nào ở đây cả). Vậy thì chỉ cần tắt hydrate cho những Component kiểu như vậy, hoặc là chỉ Hydrate khi nào có component nhảy vào màn hình (Viewport) của user.

Untitled 2.png

Cái này khá dễ để làm, cùng package react-hydration-on-demand là được

import withHydrationOnDemand from"react-hydration-on-demand";import Card from"../Card";// Hydrate when the component enters the viewportconst CardWithHydrationOnDemand =withHydrationOnDemand({ on:["visible"]})(
    Card
);exportdefaultclassAppextendsReact.Component{render(){return(<CardWithHydrationOnDemandtitle="my card"wrapperProps={{
                    className:"customClassName",
                    style:{ display:"contents"},}}/>);}}

Vậy là bây giờ, cái gạch đầu dòng thứ 3 đã được optimize – giảm thời gian JS phải chạy để hydrate cái landing page yếu dấu của chúng ta 🥰

Lazy load component rồi hydrate khi cần thiết

Ở bước trên, ta có thể optimize executed time sử dụng react-hydration-on-demand nhưng nếu nhìn vào đống JS được gửi xuống bạn sẽ nhận ra

JS cho các component vẫn phải được download và parsed, nó chỉ đơn giản là không hoặc chưa execute thôi.
💡 Có cách nào mà mình vẫn render được full HTML nhưng chỉ load JS và Hydrate Component đó khi cần thiết không?

Trong quá trình tìm kiếm câu trả lời, thì đây là giải pháp mình thấy ưng ý nhất: https://www.patterns.dev/posts/islands-architecture/

Untitled 3.png

Ý tưởng thì khá đơn giản:

  • Render full trang ở quá trình SSR
  • Load tối thiểu JS, chỉ để listen trên cây DOM xem có event nào không
  • Nếu mà có event, thì load JS tương ứng rồi chạy nó thôi

Giải pháp này thực sự optimize performance rất rất nhiều, bằng cách hy sinh một chút thời gian mỗi khi user có interactive gì đó. Với mình cái trade-off này là cực kì “lời” 🌟

Nếu thử disable JS thì  TTI giảm hơn 7 lần. Sẽ làm sao nếu chúng ta chỉ cần giảm một nửa trong số đó?

Nếu thử disable JS thì TTI giảm hơn 7 lần. Sẽ làm sao nếu chúng ta chỉ cần giảm một nửa trong số đó?

Đỉnh của chóp! Giải pháp khá dễ hiểu tuy nhiên ở thời điểm hiện tại thì khá khó để làm. Tại sao?

  • Ở thời điểm hiện tại, React chỉ support hydrate full một app chứ không phải riêng từng component (Nếu v18 được hoàn thiện thì sẽ giải quyết được cái này). Thực ra cái package react-hydration-on-demand nó có một số trick để bỏ qua quá trình Hydrate
  • Với Nextjs, nếu component được define là dynamic mà nếu nó được render ở quá trình SSR, thì đống JS của nó cũng được gửi xuống Browser ngay khi page load luôn, chả có gì gọi là lazy ở đây cả

Đọc thêm

Why Progressive Hydration is Harder than You Think

Vậy là mình quyết định viết một cái package có thể:

  • Bỏ qua quá trình Hydrate. Hầu hết là dựa theo thằng react-hydration-on-demand thôi 😃
  • Loại bỏ JS khi load page và khiến mình có thể tùy chỉnh khi nào thì load JS tương ứng

Làm sao mình làm được á hả? Xem thử ở đây nè (khá ngắn)

Còn đây là kết quả

https://user-images.githubusercontent.com/9281080/172079813-a49db8c0-c64d-4589-941d-bf027b22433a.mov

Cách dùng

Install

npminstall next-lazy-hydrate
yarnadd next-lazy-hydrate

Usage

import lazyHydrate from'next-lazy-hydrate';// Static componentconst WhyUs =lazyHydrate(()=>import('../components/whyus'));// Lazy hydrate when users hover the componentconst Footer =lazyHydrate(()=>import('../components/footer',{ on:['hover']}));constHomePage=()=>{return(<div><AboveTheFoldComponent/>{/* ----The Fold---- */}<WhyUs/><Footer/></div>);};

Document

https://github.com/thanhlmm/next-lazy-hydrate

API khi sử dụng package khá đơn giản, hy vọng nó giúp các đồng-coder khác Optimize TTI và FID cho Nextjs một cách super đơn giản

Nhớ Star ⭐ cho tui nha!

Bài gốc: https://thanhle.blog/blog/optimize-tti-và-fid-cho-nextjs-mot-cach-super-don-gian

Nguồn: viblo.asia

Bài viết liên quan

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ

Cách sử dụng SFTP (Giao thức truyền file qua SSH an toàn hơn)

SFTP là cách an toàn để truyền files giữa các máy tính, gữa máy local và web hostin

Hotlinking: Key Reasons to Avoid and Methods to Protect Your Site

Hotlinking might seem an easy way to acquire website assets, but in reality, it brings several disad

Sự Khác Nhau Giữa Domain và Hosting Là Gì?

Sự khác nhau giữa domain và hosting là gì? Bài này giải thích ngắn và dễ hiểu nh