Một website chậm không chỉ khiến người dùng bỏ đi mà còn có thể ảnh hưởng tới thứ hạng tìm kiếm, vì Google sử dụng Core Web Vitals như một tín hiệu trong đánh giá trải nghiệm trang. Tin vui là nếu bạn đang dùng Next.js, rất nhiều công cụ tối ưu đã có sẵn trong framework. Vấn đề chỉ là dùng chúng đúng cách. Bài viết này đi qua ba chỉ số chính và những việc cụ thể bạn có thể làm để cải thiện từng chỉ số.

Ba chỉ số Core Web Vitals hiện nay

Theo web.dev, bộ Core Web Vitals hiện gồm:

  • LCP (Largest Contentful Paint): thời gian hiển thị phần tử nội dung lớn nhất trong khung nhìn. Mức tốt là từ 2,5 giây trở xuống.
  • INP (Interaction to Next Paint): độ trễ từ lúc người dùng tương tác đến khi giao diện phản hồi. Mức tốt là từ 200 mili giây trở xuống. INP đã thay thế FID trong bộ Core Web Vitals từ năm 2024.
  • CLS (Cumulative Layout Shift): mức độ bố cục bị xê dịch bất ngờ. Mức tốt là từ 0,1 trở xuống.

Một trang được coi là đạt khi cả ba chỉ số ở mức tốt tại phân vị thứ 75 lượt tải trang, xét riêng cho mobile và desktop. Điều đó có nghĩa là bạn cần quan tâm tới người dùng có thiết bị và mạng ở mức trung bình kém, chứ không chỉ chiếc laptop mạnh của lập trình viên.

Đo trước khi tối ưu

Hãy phân biệt hai loại dữ liệu: dữ liệu phòng thí nghiệm từ Lighthouse hay PageSpeed Insights, hữu ích khi debug; và dữ liệu thực tế từ người dùng thật, chẳng hạn báo cáo Core Web Vitals trong Google Search Console. Trong Next.js, bạn có thể thu thập số liệu thực tế bằng hook useReportWebVitals rồi gửi về hệ thống phân tích của mình. Luôn đo trước, tối ưu sau, rồi đo lại để xác nhận.

Cải thiện LCP

Phần tử LCP thường là ảnh hero, banner hoặc khối tiêu đề lớn. Các bước nên làm:

  1. Dùng next/image để tự động sinh ảnh đúng kích thước, định dạng hiện đại và lazy-load cho ảnh bên dưới màn hình đầu.
  2. Ưu tiên tải ảnh LCP. Theo tài liệu Next.js, từ phiên bản 16 thuộc tính priority đã bị đánh dấu deprecated; thay vào đó bạn dùng preload, hoặc trong đa số trường hợp là loading="eager" hay fetchPriority="high" cho ảnh hero.
  3. Khai báo sizes chính xác cho ảnh responsive để trình duyệt không tải ảnh lớn hơn cần thiết.
  4. Render nội dung chính trên server. Server Components và tạo trang tĩnh giúp HTML có sẵn nội dung ngay, thay vì chờ JavaScript tải về rồi mới gọi API.
  5. Giảm thời gian phản hồi server bằng cache dữ liệu và triển khai gần người dùng qua CDN.
import Image from "next/image";
 
export function Hero() {
  return (
    <Image src="/hero.webp" alt="Giải pháp phần mềm Besoft"
      width={1600} height={900} sizes="100vw" fetchPriority="high" />
  );
}

Cải thiện INP

INP kém thường do luồng chính bị chặn bởi quá nhiều JavaScript. Hướng xử lý:

  • Giảm JavaScript gửi xuống client. Giữ component ở server khi không cần tương tác, chỉ đặt "use client" cho đúng mảnh giao diện cần thiết.
  • Tải chậm thành phần nặng như biểu đồ, trình soạn thảo, bản đồ bằng next/dynamic để chúng không nằm trong bundle ban đầu.
  • Kiểm soát script bên thứ ba. Dùng next/script với chiến lược lazyOnload cho chat widget, công cụ quảng cáo hay analytics không quan trọng.
  • Chia nhỏ tác vụ dài. Với xử lý nặng trong event handler, hãy cập nhật giao diện trước rồi đẩy phần tính toán ra sau, hoặc dùng useTransition để đánh dấu cập nhật không khẩn cấp.
  • Debounce các input như ô tìm kiếm thay vì xử lý mỗi lần gõ phím.

Cải thiện CLS

CLS cao làm người dùng bấm nhầm và cảm thấy trang "chập chờn". Nguyên nhân phổ biến và cách khắc phục:

  • Ảnh không có kích thước: next/image yêu cầu width và height, hoặc dùng fill trong khung có kích thước xác định, nên tự động giữ chỗ.
  • Font thay đổi khi tải xong: dùng next/font để tự host font và điều chỉnh font dự phòng, hạn chế việc chữ nhảy khi font chính được áp dụng.
  • Nội dung chèn động: banner cookie, quảng cáo hay thông báo nên được dành sẵn không gian, hoặc hiển thị dạng lớp phủ thay vì đẩy nội dung xuống.
  • Skeleton đúng kích thước: khi dùng loading.tsx hay Suspense, hãy làm khung chờ có kích thước gần với nội dung thật.
import { Inter } from "next/font/google";
 
const inter = Inter({ subsets: ["latin", "vietnamese"], display: "swap" });

Lưu ý khai báo subset vietnamese để chữ có dấu hiển thị đúng với font đã tối ưu.

Biến tối ưu thành thói quen

Hiệu năng dễ "trôi" dần theo thời gian khi tính năng mới được thêm vào. Một số cách để giữ vững:

  • Đặt ngân sách hiệu năng, chẳng hạn giới hạn kích thước bundle, và kiểm tra trong CI.
  • Theo dõi dữ liệu thực tế hằng tuần thay vì chỉ chạy Lighthouse một lần trước khi ra mắt.
  • Review kỹ mỗi thư viện mới trước khi thêm vào dự án.

Kết luận

Next.js cung cấp gần như đủ công cụ để đạt Core Web Vitals tốt: next/image cho LCP và CLS, next/font cho font ổn định, Server Components cùng next/dynamic và next/script để giảm tải JavaScript cho INP. Chìa khóa là đo bằng dữ liệu thật, xác định đúng nút thắt và xử lý từng chỉ số một cách có hệ thống. Một website nhanh mang lại trải nghiệm tốt cho người dùng, và đó cũng là điều công cụ tìm kiếm muốn thấy.

Nguồn tham khảo