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