React Code Splitting Stratejileri

React Code Splitting Stratejileri
Modern React uygulamaları büyüdükçe, JavaScript bundle boyutu da artar ve sayfa yüklenme süreleri uzar. Code splitting, uygulamanızı daha küçük parçalara bölerek sadece ihtiyaç duyulan kodu yüklemenizi sağlar. Bu rehberde, React'te code splitting'in farklı stratejilerini, Webpack ve Vite yapılandırmalarını ve gerçek dünya optimizasyon tekniklerini adım adım ele alacağız.
Code Splitting Nedir?
Code splitting, tek bir büyük JavaScript dosyası yerine birden fazla küçük dosya (chunk) oluşturma tekniğidir. Kullanıcı uygulamaya girdiğinde yalnızca o anda gerekli olan chunk yüklenir, geri kalanı ihtiyaç duyulduğunda lazy olarak çekilir. Bu, özellikle Time to Interactive (TTI) ve Largest Contentful Paint (LCP) metriklerini iyileştirir.
1. Route Bazlı Code Splitting
En yaygın ve etkili strateji, her route'u ayrı bir chunk'a ayırmaktır. Kullanıcı bir sayfaya ilk kez gittiğinde o sayfanın kodu yüklenir.
import React, { Suspense, lazy } from 'react';
import { BrowserRouter, Routes, Route, Link, useLocation } from 'react-router-dom';
// Her route ayrı bir chunk olarak yüklenir
const Home = lazy(() => import(/* webpackChunkName: "home" */ './pages/Home'));
const Products = lazy(() => import(/* webpackChunkName: "products" */ './pages/Products'));
const ProductDetail = lazy(() => import(/* webpackChunkName: "product-detail" */ './pages/ProductDetail'));
const Cart = lazy(() => import(/* webpackChunkName: "cart" */ './pages/Cart'));
const Checkout = lazy(() => import(/* webpackChunkName: "checkout" */ './pages/Checkout'));
const Admin = lazy(() => import(/* webpackChunkName: "admin" */ './pages/Admin'));
// Route bazlı loading component
function RouteLoader() {
return (
<div className="flex items-center justify-center min-h-[400px]">
<div className="text-center">
<div className="animate-spin rounded-full h-10 w-10 border-b-2 border-blue-600 mx-auto" />
<p className="mt-3 text-gray-500">Sayfa yükleniyor...</p>
</div>
</div>
);
}
function App() {
return (
<BrowserRouter>
<nav className="bg-white shadow p-4">
<Link to="/" className="mr-4">Ana Sayfa</Link>
<Link to="/products" className="mr-4">Ürünler</Link>
<Link to="/cart" className="mr-4">Sepet</Link>
</nav>
<Suspense fallback={<RouteLoader />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products />} />
<Route path="/products/:id" element={<ProductDetail />} />
<Route path="/cart" element={<Cart />} />
<Route path="/checkout" element={<Checkout />} />
<Route path="/admin/*" element={<Admin />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
2. Component Bazlı Code Splitting
Ağır componentler (editörler, grafikler, haritalar) için component seviyesinde lazy loading uygulayabilirsiniz.
import { lazy, Suspense, useState } from 'react';
// Ağır kütüphaneler sadece gerektiğinde yüklenir
const RichTextEditor = lazy(() => import('./components/RichTextEditor'));
const ChartDashboard = lazy(() => import('./components/ChartDashboard'));
const MapView = lazy(() => import('./components/MapView'));
function ProductPage() {
const [showEditor, setShowEditor] = useState(false);
const [activeTab, setActiveTab] = useState<'info' | 'chart' | 'map'>('info');
return (
<div>
<h1>Ürün Detayları</h1>
{/* Editör sadece butona tıklanınca yüklenir */}
<button onClick={() => setShowEditor(true)}>Açıklamayı Düzenle</button>
{showEditor && (
<Suspense fallback={<div className="h-64 bg-gray-100 animate-pulse rounded" />}>
<RichTextEditor />
</Suspense>
)}
{/* Tab bazlı lazy loading */}
<div className="flex gap-2 mt-6">
<button onClick={() => setActiveTab('info')}>Bilgi</button>
<button onClick={() => setActiveTab('chart')}>Grafikler</button>
<button onClick={() => setActiveTab('map')}>Harita</button>
</div>
<Suspense fallback={<div className="h-96 bg-gray-100 animate-pulse rounded mt-4" />}>
{activeTab === 'chart' && <ChartDashboard />}
{activeTab === 'map' && <MapView />}
</Suspense>
</div>
);
}
import(/* webpackChunkName: "editor" */ './Editor'). Bu, DevTools Network sekmesinde hangi chunk'ın yüklendiğini kolayca görmenizi sağlar.
3. Prefetch ve Preload Stratejileri
import { lazy, Suspense, useCallback } from 'react';
// Lazy component tanımları
const CheckoutPage = lazy(() => import('./pages/Checkout'));
const AdminPage = lazy(() => import('./pages/Admin'));
// Prefetch fonksiyonu — idle zamanında yükle
function prefetchComponent(importFn: () => Promise<any>) {
// requestIdleCallback ile tarayıcı boştayken yükle
if ('requestIdleCallback' in window) {
requestIdleCallback(() => importFn());
} else {
setTimeout(() => importFn(), 200);
}
}
function CartSummary() {
// Kullanıcı sepeti görüntülüyorsa, muhtemelen checkout'a gidecektir
// Bu nedenle checkout sayfasını önceden yükle
const handleMouseEnter = useCallback(() => {
prefetchComponent(() => import('./pages/Checkout'));
}, []);
return (
<div>
<h2>Sepet Özeti</h2>
<p>Toplam: 450 TL</p>
<a
href="/checkout"
onMouseEnter={handleMouseEnter}
onFocus={handleMouseEnter}
className="bg-green-600 text-white px-6 py-3 rounded inline-block"
>
Ödemeye Geç
</a>
</div>
);
}
// Vite ile prefetch: link tag'ı ekleme
function addPrefetchLink(href: string) {
const link = document.createElement('link');
link.rel = 'prefetch';
link.href = href;
document.head.appendChild(link);
}
4. Bundle Analizi
// Vite için bundle analizi
// npm install -D rollup-plugin-visualizer
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
react(),
visualizer({
filename: './dist/stats.html',
open: true,
gzipSize: true,
brotliSize: true,
}),
],
build: {
rollupOptions: {
output: {
manualChunks: {
// Vendor chunk'ları ayır
'react-vendor': ['react', 'react-dom'],
'router': ['react-router-dom'],
'ui': ['framer-motion', '@radix-ui/react-dialog'],
'query': ['@tanstack/react-query'],
},
},
},
},
});
Performans Metrikleri
| Metrik | Code Splitting Öncesi | Code Splitting Sonrası |
|---|---|---|
| İlk Bundle Boyutu | ~500 KB | ~120 KB |
| Time to Interactive | ~4.5s | ~1.8s |
| LCP | ~3.2s | ~1.5s |
Sonuç
Code splitting, React uygulamalarının performansını iyileştirmenin en etkili yollarından biridir. Route bazlı splitting ile başlayın, ağır componentler için component bazlı splitting uygulayın, prefetch ile kullanıcı deneyimini optimize edin ve bundle analizi ile sonuçları ölçün. Unutmayın: Ölçemediğinizi optimize edemezsiniz.