Web Performance Rehberi
📌 Ne Zaman Kullanılır?
- ✅ Her web projesi — performans SEO ve kullanıcı deneyimi için kritik
- ⚠️ Premature optimization'dan kaçının — önce ölçün, sonra optimize edin
- ❌ —
Önerilen Kullanım: Production öncesi performans audit + sürekli monitoring Araçlar: Lighthouse, PageSpeed Insights, WebPageTest, Chrome DevTools
1) Core Web Vitals
Google'un web deneyimini olcmek için belirledigi uc temel metrik. Arama siralamasini dogrudan etkiler.
LCP — Largest Contentful Paint
Sayfadaki en büyük gorsel veya metin blogunun render süresi. <img>, <video> poster, CSS background-image ve büyük metin bloklari LCP element olabilir.
Iyilestirme: Hero image'i preload et, TTFB'yi dusur (< 800ms), render-blocking kaynaklari azalt, gorselleri optimize et (WebP/AVIF).
<link rel="preload" as="image" href="/hero.webp" type="image/webp">FID / INP — First Input Delay / Interaction to Next Paint
FID (eski): Ilk etkilesimden tarayici yanitina kadar gecen sure. INP (yeni, Mart 2024): Tüm etkilesimlerin yanit suresini olcer, en kotu etkilesimi baz alir.
Iyilestirme: Uzun main thread gorevlerini parcala, heavy computation'lari Web Worker'a tasi, gereksiz JS'i lazy load et.
// Uzun gorevleri parcalama
async function processLargeList(items) {
for (let i = 0; i < items.length; i++) {
processItem(items[i]);
if (i % 5 === 0) await new Promise(r => setTimeout(r, 0)); // yield
}
}CLS — Cumulative Layout Shift
İçerik kaymasini olcer. Gorsellere width/height belirtin, reklam alanlarina sabit boyut verin, font-display: optional kullanin.
<img src="photo.webp" width="800" height="600" alt="Aciklama">
<style>.hero { aspect-ratio: 16 / 9; width: 100%; }</style>Hedef Degerler Tablosu
| Metrik | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP | < 2.5s | 2.5s - 4.0s | > 4.0s |
| INP | < 200ms | 200ms - 500ms | > 500ms |
| CLS | < 0.1 | 0.1 - 0.25 | > 0.25 |
| FID (eski) | < 100ms | 100ms - 300ms | > 300ms |
| TTFB | < 800ms | 800ms - 1800ms | > 1800ms |
| FCP | < 1.8s | 1.8s - 3.0s | > 3.0s |
Olcum:
import { onLCP, onINP, onCLS } from 'web-vitals';
onLCP(m => sendToAnalytics({ name: 'LCP', value: m.value, id: m.id }));
onINP(m => sendToAnalytics({ name: 'INP', value: m.value, id: m.id }));
onCLS(m => sendToAnalytics({ name: 'CLS', value: m.value, id: m.id }));2) Lighthouse
Google'un performans audit araci. Performance, Accessibility, Best Practices, SEO kategorilerinde analiz yapar.
Chrome DevTools ile
F12 > Lighthouse sekmesi > Kategorileri seç > "Analyze page load". Incognito modda calistirin — extension'lar sonuclari etkiler.
CLI Kullanimi
npm install -g lighthouse
lighthouse https://example.com --output html --output-path ./report.html
lighthouse https://example.com --only-categories=performance
lighthouse https://example.com --preset=desktop # Desktop moduCI Entegrasyonu — Lighthouse CI
npm install --save-dev @lhci/cli// lighthouserc.js
module.exports = {
ci: {
collect: {
url: ['http://localhost:3000'],
startServerCommand: 'npm run start',
numberOfRuns: 3,
},
assert: {
assertions: {
'categories:performance': ['error', { minScore: 0.9 }],
'categories:accessibility': ['warn', { minScore: 0.9 }],
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
},
},
upload: { target: 'temporary-public-storage' },
},
};# .github/workflows/lighthouse.yml
name: Lighthouse CI
on: [push, pull_request]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci && npm run build
- run: npx @lhci/cli autorunSkor Kategorileri
| Kategori | Açıklama | Hedef |
|---|---|---|
| Performance | Sayfa hizi, yuklenme sureleri | 90+ |
| Accessibility | Erisebilirlik | 90+ |
| Best Practices | Modern standartlara uyum | 90+ |
| SEO | Arama motoru optimizasyonu | 90+ |
Skor renkleri: 0-49 kirmizi, 50-89 turuncu, 90-100 yesil.
3) Image Optimization
Gorseller genellikle toplam sayfa boyutunun %50+'sini olusturur.
Format Karşılaştırma
| Format | Boyut | Kalite | Seffaflik | Browser Support |
|---|---|---|---|---|
| JPEG | Orta | Iyi (lossy) | Hayir | Tüm tarayicilar |
| PNG | Büyük | Mükemmel (lossless) | Evet | Tüm tarayicilar |
| WebP | Küçük (%25-35 JPEG'den) | Cok iyi | Evet | %97+ |
| AVIF | En küçük (%50 JPEG'den) | En iyi | Evet | %92+ |
| SVG | Değişken (vektor) | Sinirsiz ölçek | Evet | Tüm tarayicilar |
Strateji: Fotograflar: AVIF > WebP > JPEG. Ikonlar/logolar: SVG.
Lazy Loading ve Responsive Images
<!-- picture ile format fallback -->
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="Hero" width="1200" height="800">
</picture>
<!-- Lazy loading — above-the-fold haric tum gorsellere -->
<img src="photo.webp" alt="..." loading="lazy" width="400" height="300">
<!-- LCP element — eager + high priority -->
<img src="hero.webp" alt="Hero" loading="eager" fetchpriority="high">
<!-- Responsive images — srcset + sizes -->
<img
srcset="photo-400w.webp 400w, photo-800w.webp 800w, photo-1200w.webp 1200w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 33vw"
src="photo-800w.webp" alt="..." loading="lazy"
>Next.js — next/image
import Image from 'next/image';
import heroImg from '@/public/hero.jpg';
// Statik import — otomatik boyut + blur placeholder
<Image src={heroImg} alt="Hero" priority placeholder="blur" />
// Remote image — boyut zorunlu
<Image src="https://example.com/photo.jpg" alt="..." width={800} height={600}
quality={80} sizes="(max-width: 768px) 100vw, 50vw" />
// Fill modu — parent'i doldurur
<div style={{ position: 'relative', height: 400 }}>
<Image src="/bg.jpg" alt="..." fill style={{ objectFit: 'cover' }} />
</div>Nuxt Image
<NuxtImg src="/hero.jpg" width="800" height="600" format="webp" quality="80" loading="lazy" />
<NuxtPicture src="/hero.jpg" format="avif,webp" width="1200" height="800" />Sharp ile Server-Side Optimize
const sharp = require('sharp');
await sharp('input.jpg').resize(800, 600, { fit: 'cover' }).webp({ quality: 80 }).toFile('output.webp');
await sharp('input.jpg').resize(1200).avif({ quality: 50 }).toFile('output.avif');
// Birden fazla boyut
for (const size of [400, 800, 1200, 1600]) {
await sharp('input.jpg').resize(size).webp({ quality: 80 }).toFile(`output-${size}w.webp`);
}4) Font Optimization
Web fontlari render'i geciktirebilir. Doğru strateji ile metin hemen gorunur, layout shift onlenir.
font-display
| Deger | Davranis | Kullanım |
|---|---|---|
swap | Fallback göster, font yuklenince değiştir | En yaygin, FOIT'i onler |
optional | Fallback göster, font yuklenmediyse kalir | CLS'i tamamen onler |
fallback | 100ms bekle, 3s icinde yuklenmezse fallback kalir | Orta yol |
block | 3s gorunmez bekle | Sadece ikon fontlari |
FOUT vs FOIT
- FOUT (Flash of Unstyled Text): Metin fallback ile gorunur, sonra degisir. Çözüm:
font-display: optional - FOIT (Flash of Invisible Text): Metin gorunmez bekler. Çözüm:
font-display: swap
Font Subset ve Preload
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: swap;
unicode-range: U+0000-00FF, U+011E-011F, U+0130-0131, U+015E-015F; /* Latin + Turkce */
}<link rel="preload" href="/fonts/custom.woff2" as="font" type="font/woff2" crossorigin># pyftsubset ile subset olusturma
pyftsubset "Font.ttf" --output-file="Font-subset.woff2" --flavor=woff2 \
--unicodes="U+0000-00FF,U+011E-011F,U+0130-0131,U+015E-015F"Next.js — next/font
import { Inter } from 'next/font/google';
import localFont from 'next/font/local';
const inter = Inter({ subsets: ['latin', 'latin-ext'], display: 'swap', variable: '--font-inter' });
const custom = localFont({
src: [
{ path: './fonts/Custom-Regular.woff2', weight: '400' },
{ path: './fonts/Custom-Bold.woff2', weight: '700' },
],
display: 'swap',
});
// layout.tsx
<html className={inter.variable}><body className={inter.className}>{children}</body></html>Variable Fonts
Tek dosyada tüm agirliklar (100-900). Daha az HTTP istegi, daha küçük toplam boyut.
@font-face {
font-family: 'InterVariable';
src: url('/fonts/Inter-Variable.woff2') format('woff2-variations');
font-display: swap;
font-weight: 100 900;
}Self-Hosting vs CDN
| Kriter | Self-Hosting | CDN (Google Fonts) |
|---|---|---|
| Performans | Daha iyi (ayni origin) | Ek DNS + bağlantı |
| Gizlilik | GDPR uyumlu | IP Google'a gider |
| Kontrol | Tam (subset, format) | Sınırlı |
Öneri: Self-hosting tercih edin. next/font veya Fontsource kullanin.
5) JavaScript Performance
JavaScript sayfanin en pahali kaynagi — parse, compile ve execute main thread'i bloklar.
Code Splitting
// Dynamic import — ihtiyac duyulunca yukle
const loadChart = async () => {
const { Chart } = await import('./chart-library');
Chart.render(data);
};// React.lazy ile component splitting
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./Dashboard'));
const Settings = lazy(() => import('./Settings'));
<Suspense fallback={<Spinner />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>Next.js App Router'da her page.tsx otomatik ayri chunk olusturur.
Tree Shaking
// KOTU — tum kutuphane (~70KB)
import _ from 'lodash';
// IYI — sadece kullanilan fonksiyon (~2KB)
import get from 'lodash/get';
// DAHA IYI — ES module (tree-shakeable)
import { get } from 'lodash-es';Gereksinimler: ES Modules kullanin, package.json'da "sideEffects": false ekleyin.
Bundle Analysis
// vite.config.js
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [visualizer({ open: true, gzipSize: true, brotliSize: true })],
});
// next.config.js — @next/bundle-analyzer
const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true' });
module.exports = withBundleAnalyzer({});
// ANALYZE=true npm run builddefer vs async
| Özellik | Normal | async | defer |
|---|---|---|---|
| HTML parse'i bloklar | Evet | Kismen | Hayir |
| Sira garantili | Evet | Hayir | Evet |
| Kullanım | — | Analytics, reklamlar | Uygulama kodu |
<script defer src="app.js"></script>
<script async src="analytics.js"></script>Third-Party Script — Partytown
Third-party script'leri Web Worker'a tasiyarak main thread'i serbest birakir.
<script type="text/partytown" src="https://www.googletagmanager.com/gtag/js?id=GA_ID"></script>// Next.js
<Script src="https://www.googletagmanager.com/gtag/js?id=GA_ID" strategy="worker" />6) CSS Performance
Critical CSS
Above-the-fold CSS'i inline olarak HTML'e gomun, geri kalani asenkron yukleyin.
<head>
<style>
body { margin: 0; font-family: system-ui, sans-serif; }
.header { background: #1a1a2e; color: white; padding: 1rem; }
.hero { padding: 4rem 2rem; text-align: center; }
</style>
<link rel="preload" href="/styles/main.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles/main.css"></noscript>
</head>PurgeCSS / Tailwind Purge
Kullanilmayan CSS kurallarini kaldirir. Tailwind CSS v3+ otomatik purge yapar — sadece content doğru ayarlanmali.
// tailwind.config.js
module.exports = {
content: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
};contain, will-change, content-visibility
/* contain — layout/paint hesaplamalarini izole eder */
.card { contain: layout style paint; }
/* will-change — SADECE animasyon oncesi, sonra kaldirin */
.card:hover { will-change: transform; }
/* * { will-change: transform; } YAPMAYIN — bellek israfi */
/* content-visibility — gorunmeyen elementlerin render'ini erteler */
.list-item {
content-visibility: auto;
contain-intrinsic-size: auto 200px; /* scroll bar icin tahmini boyut */
}content-visibility: auto uzun sayfalarda ilk render suresini %50+ azaltabilir.
7) Network Optimization
HTTP/2 Multiplexing
Tek TCP baglantisi uzerinden birden fazla istek ayni anda. Domain sharding ve sprite birlestirme artik gereksiz.
Compression — gzip vs Brotli
| Özellik | gzip | Brotli |
|---|---|---|
| Sikistirma orani | Iyi | %15-25 daha iyi |
| Hiz | Hızlı | Yavas (statik için sorun degil) |
| Browser Support | Tüm tarayicilar | %97+ (HTTPS gerekli) |
# Nginx
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript text/xml image/svg+xml;
gzip on;
gzip_comp_level 6;CDN
| CDN | Avantaj | Kullanım |
|---|---|---|
| Cloudflare | Ücretsiz plan, DDoS korumasi | Genel amacli |
| Vercel Edge | Next.js entegrasyonu | Next.js projeleri |
| AWS CloudFront | AWS ekosistemi | AWS altyapisi |
Resource Hints
| Hint | Ne Yapar | Kullanım |
|---|---|---|
preload | Kesinlikle gereken kaynagi hemen indir | Font, critical CSS, hero image |
prefetch | Sonraki sayfa kaynagini bosta iken indir | Sonraki sayfa bundle'i |
preconnect | Onceden TCP+TLS baglantisi kur | API sunucusu, CDN |
dns-prefetch | Sadece DNS cozumle (hafif) | Düşük oncelikli 3rd-party domain |
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preconnect" href="https://api.example.com">
<link rel="dns-prefetch" href="https://analytics.example.com">
<link rel="prefetch" href="/about/page.js">Fazla preload ters etki yapar. preconnect en fazla 4-6 domain için kullanin.
8) Caching
Cache-Control Header
# Hash'li statik asset'ler (JS, CSS, image)
Cache-Control: public, max-age=31536000, immutable
# HTML sayfalari
Cache-Control: public, max-age=0, must-revalidate
# API yanitlari
Cache-Control: private, max-age=60, stale-while-revalidate=300
# Hassas veri
Cache-Control: no-store| Direktif | Anlam |
|---|---|
public | CDN + tarayici cache'leyebilir |
private | Sadece tarayici (CDN hayir) |
max-age=N | N saniye cache'ten sun |
s-maxage=N | CDN için ayri max-age |
stale-while-revalidate=N | Eski cache'i sun, arka planda yenile |
immutable | Cache süresi boyunca sunucuya sorma |
no-store | Hicbir yerde cache'leme |
ETag / Last-Modified
Sunucu ETag header'i gonderir. Sonraki isteklerde tarayici If-None-Match ile sorar. Degismediyse 304 Not Modified doner (body bos, bant genisligi tasarrufu).
Service Worker — Offline Cache
const CACHE_NAME = 'app-v1';
const ASSETS = ['/', '/index.html', '/styles/main.css', '/scripts/app.js'];
self.addEventListener('install', e => {
e.waitUntil(caches.open(CACHE_NAME).then(c => c.addAll(ASSETS)));
});
self.addEventListener('fetch', e => {
e.respondWith(
caches.match(e.request).then(cached =>
cached || fetch(e.request).then(res => {
caches.open(CACHE_NAME).then(c => c.put(e.request, res.clone()));
return res;
})
)
);
});Stratejiler: Cache-first (statik asset), Network-first (API), Stale-while-revalidate (feed).
Immutable Assets — Hash Filename
Build ciktisinda app.a1b2c3d4.js seklinde hash eklenir. İçerik degisince hash degisir, yeni dosya adi olusur. Boylece immutable guvenle kullanilir. Vite/Webpack bunu otomatik yapar.
9) Rendering Stratejileri
| Özellik | CSR | SSR | SSG | ISR |
|---|---|---|---|---|
| Render nerede | Tarayici | Sunucu (her istek) | Build time | Build + periyodik |
| Ilk yükleme | Yavas FCP | Hızlı FCP | En hızlı | Hızlı (cache) |
| SEO | Kotu | Mükemmel | Mükemmel | Mükemmel |
| Veri tazeligi | Guncel | Guncel | Build anindaki | Periyodik güncelleme |
| Sunucu yuku | Yok | Yüksek | Yok | Düşük |
| Kullanım | Dashboard, SPA | E-ticaret | Blog, docs | Haber, katalog |
Next.js örnekleri:
// SSG — build time'da statik olustur
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map(post => ({ slug: post.slug }));
}
// SSR — her istekte taze veri
const data = await fetch('https://api.example.com/data', { cache: 'no-store' });
// ISR — belirli araliklarla yenile
const data = await fetch('https://api.example.com/products', { next: { revalidate: 3600 } });10) React Performance
React.memo, useMemo, useCallback
import { memo, useMemo, useCallback, useState } from 'react';
const ExpensiveList = memo(function ExpensiveList({ items, onSelect }) {
return <ul>{items.map(i => <li key={i.id} onClick={() => onSelect(i.id)}>{i.name}</li>)}</ul>;
});
function App() {
const [count, setCount] = useState(0);
const [items] = useState([{ id: 1, name: 'A' }, { id: 2, name: 'B' }]);
const handleSelect = useCallback((id) => console.log(id), []);
const sorted = useMemo(() => [...items].sort((a, b) => a.name.localeCompare(b.name)), [items]);
return (
<div>
<button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
<ExpensiveList items={sorted} onSelect={handleSelect} />
</div>
);
}Ne zaman kullanilir:
| Durum | Arac |
|---|---|
| Pahali hesaplama (sort, filter) | useMemo |
| Child'a gecen callback | useCallback |
| Sik render olan büyük liste | React.memo |
| Basit component, basit props | Optimizasyon gereksiz |
Kural: Once React Profiler ile yavas component'leri tespit edin, sonra optimize edin.
Virtualization — react-window
import { FixedSizeList } from 'react-window';
// 10.000 satir — sadece gorunen ~20 satir render edilir
<FixedSizeList height={600} itemCount={items.length} itemSize={50} width="100%">
{({ index, style }) => <div style={style}>{items[index].name}</div>}
</FixedSizeList>Suspense ve Lazy Loading
const HeavyChart = lazy(() => import('./HeavyChart'));
<Suspense fallback={<div style={{ height: 400, background: '#e0e0e0' }} />}>
<HeavyChart />
</Suspense>React Profiler
Chrome DevTools > React DevTools > Profiler sekmesi > Record > Etkilesim > Stop > Flame chart'ta yavas component'leri bul. "Why did this render?" ile gereksiz render'lari tespit edin.
<Profiler id="MainContent" onRender={(id, phase, actualDuration) => {
console.log(id, phase, actualDuration + 'ms');
}}>
<MainContent />
</Profiler>11) Database Query Performance
N+1 Problem
// KOTU — 1 + N sorgu
const posts = await Post.findAll();
for (const post of posts) {
post.author = await User.findById(post.userId); // Her post icin ayri sorgu
}
// IYI — 2 sorgu (eager loading)
const posts = await Post.findAll({ include: [{ model: User, as: 'author' }] });Indexing
CREATE INDEX idx_posts_user_id ON posts(user_id);
CREATE INDEX idx_posts_user_date ON posts(user_id, created_at); -- compositeDetayli bilgi için veritabani rehberlerine bakiniz.
12) Monitoring
PageSpeed Insights
pagespeed.web.dev — Lab data (Lighthouse) + Field data (gercek kullanici, son 28 gun).
WebPageTest
webpagetest.org — Waterfall chart, film strip, farkli lokasyon/cihaz testi. Waterfall'da uzun mor cubuk = yavas sunucu (backend optimize edin), uzun mavi cubuk = büyük dosya (sikistirin).
Chrome DevTools Performance Tab
F12 > Performance > Record > Etkilesim > Stop. Flame chart'ta sari = JavaScript, mor = Layout, yesil = Paint. Experience satirindaki kirmizi ucgenler layout shift olaylarini gosterir.
Real User Monitoring (RUM)
window.addEventListener('load', () => {
setTimeout(() => {
const nav = performance.getEntriesByType('navigation')[0];
const fcp = performance.getEntriesByType('paint')
.find(p => p.name === 'first-contentful-paint')?.startTime;
navigator.sendBeacon('/api/metrics', JSON.stringify({
ttfb: nav.responseStart - nav.requestStart,
domReady: nav.domContentLoadedEventEnd - nav.startTime,
fcp,
connection: navigator.connection?.effectiveType,
}));
}, 1000);
});RUM araçları: Vercel Analytics, Sentry Performance, Google Analytics 4, Datadog RUM.
13) Bundle Analysis
| Arac | Kullanım |
|---|---|
| webpack-bundle-analyzer | Webpack projeleri |
| rollup-plugin-visualizer | Vite projeleri |
| source-map-explorer | Source map uzerinden analiz |
| @next/bundle-analyzer | Next.js projeleri |
| bundlephobia.com | Package boyut kontrolu (online) |
# bundlesize ile CI kontrolu
npm install --save-dev bundlesize{
"bundlesize": [
{ "path": "./dist/assets/*.js", "maxSize": "200 kB", "compression": "gzip" },
{ "path": "./dist/assets/*.css", "maxSize": "50 kB", "compression": "gzip" }
]
}VS Code Import Cost extension'i her import'un boyutunu editor'de gosterir.
14) Performance Budget
Hedef Boyutlar
| Kaynak | Butce (gzipped) |
|---|---|
| Total JS | < 200 KB |
| Initial JS | < 100 KB |
| Total CSS | < 50 KB |
| Images (toplam) | < 500 KB |
| Font (toplam) | < 100 KB |
| Total page weight | < 1 MB |
Core Web Vitals Hedefleri
| Metrik | Hedef |
|---|---|
| LCP | < 2.5s |
| INP | < 200ms |
| CLS | < 0.1 |
| FCP | < 1.8s |
| TTFB | < 800ms |
| TTI | < 3.5s |
CI'da Kontrol
// lighthouserc.js
module.exports = {
ci: {
assert: {
assertions: {
'categories:performance': ['error', { minScore: 0.9 }],
'resource-summary:script:size': ['error', { maxNumericValue: 200000 }],
'resource-summary:stylesheet:size': ['error', { maxNumericValue: 50000 }],
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
},
},
},
};15) Checklist — Production Oncesi Performans Kontrol Listesi
Gorseller:
- [ ] Tüm gorseller WebP/AVIF formatinda (fallback ile)
- [ ] Gorsellere
widthveheightveyaaspect-ratiobelirtildi - [ ] Above-the-fold gorseller
loading="eager"+fetchpriority="high" - [ ] Diger gorseller
loading="lazy" - [ ] Hero image
preloadile belirtildi
Fontlar:
- [ ] WOFF2 formatinda,
font-display: swapveyaoptional - [ ] Kritik fontlar preload ile yukleniyor
- [ ] Font subset yapildi (sadece kullanilan karakterler)
JavaScript:
- [ ] Route-based code splitting uygulanmis
- [ ] Tree shaking calisiyor (ES Modules)
- [ ] Third-party script'ler defer/async/Partytown ile
- [ ] Bundle boyutu < 200KB gzipped
CSS:
- [ ] Kullanilmayan CSS kaldirildi (PurgeCSS/Tailwind purge)
- [ ] Critical CSS inline
- [ ] CSS < 50KB gzipped
Network ve Cache:
- [ ] Brotli/gzip compression aktif
- [ ] CDN kullaniliyor
- [ ] Gerekli domainler preconnect ile baglandi
- [ ] Statik asset'ler immutable cache (hash filename)
- [ ] HTML must-revalidate ile cache'leniyor
Core Web Vitals:
- [ ] LCP < 2.5s, INP < 200ms, CLS < 0.1
- [ ] Lighthouse Performance 90+
16) Tips
Premature optimization'dan kacinin. Once çalıştır, sonra olc, sonra optimize et. Tahmin etmeyin, veriyle karar verin.
Measure first. Her optimizasyon oncesi ve sonrasi olcum yapin — iyilesme mi kotulesme mi bilin.
80/20 kurali. Performans kazancinin %80'i su alanlardan gelir:
- Gorsel optimizasyonu — En büyük etki, en kolay. Format değiştir, boyut kucult, lazy load.
- JavaScript azaltma — Code splitting, tree shaking, gereksiz kütüphane kaldirma.
- Font optimizasyonu — Preload, subset, font-display: swap.
- Cache ve CDN — Immutable cache, Brotli compression.
Core Web Vitals oncelikli. Google ranking signal. Oncelik: LCP > CLS > INP.
Faydali araclar:
| Arac | Tur | Maliyet |
|---|---|---|
| Lighthouse | Lab testing | Ücretsiz |
| PageSpeed Insights | Lab + Field | Ücretsiz |
| WebPageTest | Lab testing | Ücretsiz |
| Bundlephobia | Bundle boyut | Ücretsiz |
| Squoosh | Gorsel optimizasyon | Ücretsiz |
| Unlighthouse | Toplu site audit | Ücretsiz |
Ilgili Rehberler
Frontend
- Frontend Genel Bakış
- JavaScript & TypeScript
- TypeScript Rehberi
- React Rehberi
- Next.js Rehberi
- Vue.js Rehberi
- CSS & Tailwind
- Three.js Rehberi