بازگشت به وبلاگ

Core Web Vitals و پرفورمنس در Next.js: یه راهنمای عملی

۲ مرداد ۱۴۰۵3 دقیقه مطالعه
Core Web Vitals و پرفورمنس در Next.js: یه راهنمای عملی

Core Web Vitals از همون لحظه‌ای که یه سیگنال رتبه‌بندی گوگل شدن، دیگه «خوبه داشته باشیم» نبودن — ولی دلیل واقعی اهمیت دادن بهشون ساده‌تره: تقریباً اندازه می‌گیرن که سایتت برای یه انسان واقعی سریع حس می‌شه یا نه. Next.js خیلی از ابزارهای رفعشون رو آماده داره؛ فقط باید درست ازشون استفاده کنی.

سه تا معیار، خلاصه

  • LCP (Largest Contentful Paint) — چقدر طول می‌کشه تا بزرگ‌ترین المان قابل‌مشاهده (معمولاً عکس هیرو یا یه تیتر) رندر بشه. هدف: زیر ۲.۵ ثانیه.

  • INP (Interaction to Next Paint) — صفحه چقدر به کلیک/تپ/تایپ سریع واکنش نشون می‌ده؛ از ۲۰۲۴ جایگزین FID شده. هدف: زیر ۲۰۰ میلی‌ثانیه.

  • CLS (Cumulative Layout Shift) — محتوا موقع لود شدن چقدر جابه‌جا می‌شه. هدف: زیر ۰.۱.

رفع LCP

دوتا اهرم بزرگ توی Next.js: next/image و next/font.

import Image from "next/image";

// priority لیزی-لودینگ رو برای عکس‌های above-the-fold رد می‌کنه — فقط روی
// المان LCP استفاده‌ش کن، نه همه‌جا (وگرنه کل هدفش از بین می‌ره)
<Image src="/hero.jpg" alt="" width={1200} height={630} priority />

next/image به‌صورت خودکار srcset ریسپانسیو می‌سازه و فرمت‌های مدرن (AVIF/WebP) سرو می‌کنه، پس مرورگر یه فایل متناسب با ویوپورت واقعی دانلود می‌کنه، نه یه اورجینال ۴۰۰۰ پیکسلی.

import { Inter } from "next/font/google";

// next/font فایل فونت رو خودش سلف-هاست می‌کنه و @font-face رو inline می‌کنه
// — نه درخواستی به CDN گوگل، نه رندر-بلاکینگ، نه layout shift موقع سواپ فونت
const inter = Inter({ subsets: ["latin"], display: "swap" });

رفع INP

INP معمولاً به یکی از این دوتا برمی‌گرده: جاوااسکریپت زیادی که روی main thread اجرا می‌شه، یا یه افکت کند که با هر ضربه کیبورد اجرا می‌شه.

  • کامپوننت‌های کلاینتیِ بزرگ رو با next/dynamic بشکن تا جاوااسکریپتشون توی باندل اولیه نباشه.

  • کامپوننت‌های سنگین رو به‌طور پیش‌فرض Server Component نگه دار — App Router خودش همین سمت هلت می‌ده؛ در برابر اضافه کردن "use client" مقاومت کن مگه واقعاً به تعامل نیاز داشته باشه.

  • کارهای غیرحیاتی که با ورودی trigger می‌شن (سرچ لحظه‌ای، آنالیتیکس) رو debounce یا به تعویق بنداز، نه اینکه با هر ضربه کیبورد sync اجراشون کنی.

const HeavyChart = dynamic(() => import("./heavy-chart"), {
  loading: () => <ChartSkeleton />,
  ssr: false, // اگه فقط سمت کلاینت معنی داره (مثلاً window رو می‌خونه)
});

رفع CLS

  • همیشه width/height (یا fill با یه parent سایزدار) رو روی next/image ست کن — قبل از لود شدن عکس، جاش رو رزرو می‌کنه.

  • برای تبلیغ، embed، و هرچی که async لود می‌شه یه اسکلتون با سایز ثابت رزرو کن، نذار یهو پاپ‌آپ بشه.

  • از اضافه کردن محتوا بالای محتوای موجود پرهیز کن (مثل یه بنر کوکی که position: fixed نیست) — این کلاسیک‌ترین عامل CLSه.

استراتژی رندرینگ هم یه تصمیم پرفورمنسیه

Static generation (پیش‌فرض برای صفحاتی که دسترسی داده‌ی داینامیک ندارن) و ISR (با revalidate) بهت HTML کش‌شده روی CDN می‌دن — سریع‌ترین LCP ممکن، چون اصلاً رفت‌وبرگشتی به سرور نیست. فقط برای محتوایی که واقعاً per-request باید باشه، سراغ رندرینگ کاملاً داینامیک برو.

// استاتیک ساخته می‌شه، پشت‌صحنه هر یه ساعت revalidate می‌شه
export const revalidate = 3600;

export default async function BlogPage() {
  const posts = await getPosts(); // موقع build اجرا شد، بعد هر ۳۶۰۰ ثانیه
  return <PostList posts={posts} />;
}

برای محتوایی که مجبوراً باید داینامیک باشه (یه داشبورد، یه ویو لاگین‌شده)، از Suspense boundary استفاده کن تا اسکلت استاتیک فوری رندر بشه و بخش‌های داینامیک stream بشن — همین تنها می‌تونه یه صفحه رو از چند ثانیه صفحه‌ی خالی، به یه اسکلت آنی و تقریباً قابل‌تعامل تبدیل کنه.

اندازه‌گیری واقعی

  • Lighthouse / PageSpeed Insights برای داده‌ی آزمایشگاهی موقع توسعه.

  • کتابخونه‌ی web-vitals، برای گزارش متریک کاربر واقعی (RUM) — داده‌ی آزمایشگاهی می‌تونه عالی به‌نظر برسه ولی چیزی که دستگاه/شبکه‌ی واقعی تجربه می‌کنه رو از دست بده.

  • Vercel Analytics یا یه ابزار RUM مشابه توی production، تا افت پرفورمنس به‌شکل داده دیده بشه، نه یه حس مبهم که «انگار کندتر شده».

برای متریکی بهینه‌سازی کن که منعکس‌کننده‌ی یه کاربر واقعیه که منتظره، نه فقط برای یه امتیاز Lighthouse جدا از همه‌چیز — معمولاً این دوتا هم‌نظرن، ولی وقتی نبودن، به کاربر واقعی اعتماد کن.