Next.js 15 Full-Stack Uygulama Geliştirme

Ders 3/3 35 dakika

Performance ve Core Web Vitals Optimizasyonu

LCP, CLS, INP metriklerini iyileştirme, bundle analizi, lazy loading stratejileri ve Lighthouse skorunu 100'e çıkarma.

Core Web Vitals Nedir?

Google\'ın kullanıcı deneyimini ölçen metrikleri. SEO sıralamasını doğrudan etkiler:

  • LCP (Largest Contentful Paint): En büyük içerik ne zaman yüklendi? → <2.5s olmalı
  • CLS (Cumulative Layout Shift): Sayfa ne kadar kayıyor? → <0.1 olmalı
  • INP (Interaction to Next Paint): Kullanıcı aksiyonuna yanıt süresi → <200ms olmalı

Bundle Analizi

npm install @next/bundle-analyzer
// next.config.ts
import bundleAnalyzer from "@next/bundle-analyzer";

const withBundleAnalyzer = bundleAnalyzer({
  enabled: process.env.ANALYZE === "true",
});

export default withBundleAnalyzer({});
ANALYZE=true npm run build  # Görsel bundle raporu açılır

Dinamik Import ile Code Splitting

import dynamic from "next/dynamic";

// Büyük kütüphaneleri lazy yükleyin
const GrafikBileseni = dynamic(() => import("recharts").then(m => m.LineChart), {
  loading: () => <p>Grafik yükleniyor...</p>,
  ssr: false, // Sunucuda render etme
});

// Modal — sadece açıldığında yükle
const Modal = dynamic(() => import("@/components/Modal"), {
  ssr: false,
});

React.memo ile Gereksiz Render Önleme

import { memo, useCallback, useMemo } from "react";

const PahaliBileseni = memo(function PahaliBileseni({
  veri,
  tiklamaIsleyici,
}: {
  veri: number[];
  tiklamaIsleyici: () => void;
}) {
  return <div>{veri.map(v => <span key={v}>{v}</span>)}</div>;
});

export default function Ana() {
  // useCallback — her render'da yeni fonksiyon oluşturmaz
  const tiklamaIsleyici = useCallback(() => {
    console.log("Tıklandı");
  }, []);

  // useMemo — pahalı hesaplamayı önbellekle
  const islenmisDeger = useMemo(() => {
    return uzunHesaplama(veri);
  }, [veri]);

  return <PahaliBileseni veri={islenmisDeger} tiklamaIsleyici={tiklamaIsleyici} />;
}

Image Optimizasyonu (LCP için)

// Hero görseline priority ekleyin
<Image src="/hero.jpg" alt="Hero" fill priority className="object-cover" />

// Küçük görseller için blur placeholder
<Image
  src="/profil.jpg"
  alt="Profil"
  width={100}
  height={100}
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQ..."
/>

Vercel Analytics ile İzleme

npm install @vercel/analytics @vercel/speed-insights
// app/layout.tsx
import { Analytics } from "@vercel/analytics/react";
import { SpeedInsights } from "@vercel/speed-insights/next";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        {children}
        <Analytics />
        <SpeedInsights />
      </body>
    </html>
  );
}

Önemli Noktalar

  • LCP <2.5s, CLS <0.1, INP <200ms hedefleyin
  • dynamic import ile ağır bileşenler lazy yüklenir
  • React.memo ve useCallback ile gereksiz render engellenir
  • Vercel Analytics ile gerçek kullanıcı metrikleri izlenir