Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
Web Performansını Doğru Ölçmek: Lab vs Field, CrUX, p75 ve Angular'da web-vitals ile RUM
Web performansı tek bir Lighthouse skoruyla değil, gerçek kullanıcıların LCP, INP ve CLS değerlerinin mobil ve masaüstü için ayrı ayrı 75. yüzdeliğiyle (p75) ölçülür. Lab ile field'ın neden farklı sonuç verdiğini, CrUX'in neyi topladığını, 2026'da hangi tarayıcının neyi ölçebildiğini anlatıyor; Bookstore'un Angular istemcisinde web-vitals 6 ile RUM toplayıp ASP.NET Core'da route bazında p75 ve alarm hesaplıyoruz.
Critical Rendering Path: HTML, CSS ve JavaScript Ekrana Nasıl Ulaşır, Neyi Render-Blocking Yapar?
Critical rendering path, ilk paint'e kadar tarayıcının beklediği en uzun zincirdir; head'deki stylesheet'ler render'ı, async/defer'siz script'ler parser'ı bloklar ama her blocking kaynak kritik yolda değildir. Bookstore ana sayfasının waterfall'unda font CSS'ini ve analytics'i düzeltmenin FCP'yi değiştirmediğini, asıl zincirin main.js olduğunu ölçüyor; response compression ve analytics'i load'dan sonra yükleyerek FCP'yi 2,35 sn'den 1,10 sn'ye indiriyoruz.
LCP'yi Optimize Etmek: TTFB, Resource Load Delay, Load Duration ve Render Delay'i Tek Tek Düşürmek
LCP'yi düşürmek için onu TTFB, resource load delay, load duration ve render delay olarak dört parçaya ayırıp her birine ayrı bakmak gerekir; görsel HTML'de keşfedilebilir değilse fetchpriority tek başına işe yaramaz. Bookstore ana sayfasında NgOptimizedImage priority'nin client-side render'da hiçbir şey kazandırmadığını, prerender'ın load delay'i 1,1 sn'den 27 ms'ye indirdiğini ölçüyor; SSR tuzaklarını (document, transfer cache, UseDefaultFiles) gösteriyoruz.
Görsel ve Font Optimizasyonu: AVIF/WebP, srcset, NgOptimizedImage Loader'ları ve Türkçe Karakterli Font Subset'leri
Görseli ekrandaki boyuta göre küçültüp tarayıcının kabul ettiği en iyi formatta (AVIF, WebP, JPEG) sunmak ve font'u doğru subset ve fallback metrikleriyle yüklemek, LCP ve CLS'i en çok etkileyen iki iş. Bookstore kapaklarını ASP.NET Core'da Magick.NET ile Accept'e göre kodlayıp NgOptimizedImage loader'ıyla srcset üretiyor, LCP'yi 13,7 sn'den 1,34 sn'ye indiriyoruz; latin subset'inde ğ, ş, İ'nin fallback font'a düştüğünü ve size-adjust'ın kaymayı nasıl azalttığını ölçüyoruz.
INP'yi Optimize Etmek: Input Delay, Processing ve Presentation Delay, Long Task'ları Bölmek ve Angular'da Akıcı Liste
INP'yi düşürmek için en kötü etkileşimin hangi fazda (input delay, processing, presentation delay) beklediğini bulup main thread'i bloklayan long task'ı ya bölmek ya da küçültmek gerekir. Bookstore'un 2.000 kitaplık kataloğunda zoneless Angular'ın change detection'ının bir frame callback'inde çalıştığını LoAF ile gösteriyor; computed, doğru track, scheduler.yield ve CDK virtual scroll ile INP'yi 416 ms'den 8 ms'ye indiriyoruz.
CLS'i Optimize Etmek: Boyutsuz Görseller, Geç Gelen İçerik, Font Değişimi ve @defer Placeholder'ları
CLS'i düşürmek için sonradan gelen her içeriğin yerini en baştan ayırmak gerekir: boyutlu görsel, son boyutta placeholder ve skeleton. Bookstore'un kitap sayfasına eklediğimiz "Similar books" bloğunun impact × distance hesabını ölçüyor, @defer (on viewport) ile kaymanın scroll anına taşındığını (telefonda 0,1079) gösteriyor ve slot, skeleton ve margin collapse düzeltmesiyle her senaryoda CLS'i 0'a indiriyoruz.
JavaScript Maliyetini Azaltmak: Lazy Route, @defer Trigger'ları, injectAsync ve Bundle Budget'ları
JavaScript'in maliyetini azaltmak için başlangıç kodunu route'lara bölmek, görünmeyen bölümleri @defer ile ertelemek, tıklamada gereken service'leri injectAsync ile yüklemek ve sonucu bundle budget ile korumak gerekir. Bookstore'da başlangıç kodu 383 KB'tan 359 KB'a indi, Chart.js'li admin raporu ilk yüklemeden çıktı; ama doğrudan girilen lazy sayfalarda LCP'nin 200-300 ms kötüleştiğini de ölçtük.
Angular SSR, Hydration ve Performans: Prerender, Incremental Hydration, Event Replay ve TTFB Bedeli
SSR ve prerender, LCP içeriğini HTML'e koyarak CSR'a göre FCP'yi ve LCP'yi düşürür, ama SSR her istekte render ettiği için backend'in yavaşlığını TTFB'ye ekler; çözüm kısa süreli Output Cache. Bookstore'un kitap sayfasında FCP 1,28 sn'den 0,3 sn'ye indi; hydrate on viewport ile geç hydrate olan bir bloğun transfer cache'i kaçırıp isteği tekrarladığını ve bunun event replay'i bozduğunu da ölçtük.
Navigasyonları Hızlandırmak: bfcache, Speculation Rules, Router Preloading ve Brotli/zstd Sıkıştırma
Sayfalar arası geçişi hızlandırmak için geri tuşunda bfcache'i engellememek, SPA içinde Router preloading, document navigation'larda Speculation Rules ve doğru sıkıştırma seviyesi gerekir. Bookstore'da uygulama içi geçiş 810 ms'den 207 ms'ye, katalogdaki liste 2,8 sn'den 1,6 sn'ye indi; Speculation Rules'un routerLink'li linklerde işe yaramadığını ve ASP.NET Core'un varsayılan Brotli seviyesinin JSON'u 160 KB gönderdiğini ölçtük.
2020'den 2026'ya Core Web Vitals ve Angular Performans Araçlarında Değişenler
2020'den bu yana CLS session window'lara geçti, INP Mart 2024'te FID'in yerini aldı, LCP ve INP Firefox ve Safari'de de ölçülür oldu ve 2026'da soft navigation metrikleri CrUX'e deneysel olarak girdi; Angular'da hydration, @defer, incremental hydration, zoneless ve OnPush varsayılan hale geldi. Bookstore'un ana sayfası bu serinin sonunda Lighthouse'ta 65'ten 97'ye çıktı; eski bir Angular 12 projesinde ilk bakılacak beş kalemi de çıkarıyoruz.