Lighthouse CI ve lhci assert komutunu GitHub Actions pipeline'ına entegre ederek her PR öncesinde Core Web Vitals eşik kontrolü nasıl yapılır; eşik kalibrasyonu, yanlış pozitifler ve URL stratejisi.
CWV Regresyonu Sonrası Deploy Pipeline'ına Performans Kapısı Eklemek
Bir deploy sonrasında LCP değerinin 2,5 saniyenin üzerine çıktığını fark ettiğinizde, sorunun tam olarak hangi commit'ten kaynaklandığını bulmak güçleşir. Kümülatif bir regresyon mu, tek bir PR'ın getirdiği bir kütüphane değişikliği mi, yoksa yanlış bir görsel öncelik sıralaması mı olduğunu geriye dönük araştırmak, production'da zaten yaşandıktan sonra çok daha pahalıdır. Aynı şeyi bir sonraki deploy öncesinde otomatik olarak yakalamak mümkün.
Lighthouse CI bu iş için tasarlanmış açık kaynaklı bir araç. Her PR veya deploy adımında Lighthouse çalıştırır, ölçümleri kaydeder ve tanımladığınız eşiklere göre build'i başarısız sayar. Konfigürasyonu birkaç dosyaya sığar; GitHub Actions ile birleşince performans kapısı pipeline'ın zorunlu bir adımı haline gelir.
lhci assert hangi metriği nerede keseceğini, kararsız ortamla nasıl başa çıkılacağını ve pipeline'a nasıl bağlanacağını tek yerde toplar. Eşik yanlış kalibre edilirse kapı ya gürültü üretir ya da regresyonu kaçırır.
Lighthouse CI'ı projeye bağlamak: kurulum ve temel yapı
Lighthouse CI üç bileşenden oluşur: CLI (@lhci/cli), opsiyonel bir LHCI Server ve CI entegrasyon scripti. Çoğu proje için LHCI Server gerekmez; sonuçları geçici depolamak üzere temporary-public-storage yeterlidir ya da sadece yerel assert işlemi yaparak CI adımını başarısız sayabilirsiniz.
Kurulum tek komutla tamamlanır:
npm install --save-dev @lhci/cli
Ardından proje kökünde lighthouserc.js dosyası oluşturursunuz. Bu dosya iki bölüm içerir: ci.collect (Lighthouse'un nasıl çalışacağı) ve ci.assert (hangi eşiklerin kontrol edileceği). Başlangıç yapısı şöyle görünür:
module.exports = {
ci: {
collect: {
url: ['http://localhost:3000/'],
numberOfRuns: 3,
},
assert: {
assertions: {
'categories:performance': ['error', { minScore: 0.8 }],
},
},
},
};
numberOfRuns: 3 değeri önemli. Tek bir çalıştırma gürültülü sonuç verebilir; Lighthouse CI medyan değeri alarak raporlar. Üç run makul bir denge sağlar ve CI süresini çok uzatmaz.
lighthouserc.js ile eşik tanımı: hangi metriği nerede kesersiniz
Performans skoru tek bir eşik olarak kullanışlıdır, ama LCP veya CLS gibi belirli metriklere doğrudan assert yazmak çok daha kesin sinyaller üretir. Genel skor 0.85'in altına düştüğünde nedenini bulmak, LCP'nin 2800 ms üstüne geçtiğini gördüğünüzde bulmaktan çok daha uzun sürer.
lhci assert bireysel denetim kategorilerinin yanı sıra audits anahtarıyla tek tek Lighthouse denetimlerine de eşik koymanıza izin verir:
assert: {
preset: 'lighthouse:no-pwa',
assertions: {
'first-contentful-paint': ['warn', { maxNumericValue: 1800 }],
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
'total-blocking-time': ['warn', { maxNumericValue: 300 }],
'interactive': ['warn', { maxNumericValue: 3800 }],
},
},
error düzeyi build'i keser, warn sadece çıktıda görünür. Bir metriği ilk aşamada warn olarak başlatıp ekip alıştıktan sonra error'a yükseltmek, ani çok sayıda başarısız build'in yarattığı alarmı engeller. LCP ve CLS için doğrudan error koymak yerinde; bunlar kullanıcı deneyimini doğrudan etkiliyor ve büyük sapmalar genellikle belirgin bir değişiklikle tetikleniyor.
preset: 'lighthouse:no-pwa' eklediğinizde PWA denetimleri devre dışı kalır. PWA geliştirmiyorsanız o denetimlerden gelen başarısızlıklar anlamsız gürültü üretir.
lhci assert komutu: başarısızlık modları ve çıktıyı okumak
lhci autorun collect ve assert adımlarını sırayla çalıştırır. Bir assert başarısız olduğunda CLI sıfır olmayan bir çıkış kodu döndürür; GitHub Actions adımı bu çıkış kodu üzerinden otomatik olarak başarısız sayılır.
Tipik bir başarısız çıktı şöyle görünür:
× largest-contentful-paint failure for http://localhost:3000/
expected: ≤2500
found: 3140
all values: 2980, 3140, 3210
Üç çalıştırmanın değerleri ayrı ayrı görünür. Değerler birbirine yakın ve eşiğin üstündeyse bu bir regresyondur; biri çok yüksek biri düşükse ortam kararsızdır. Başarılı çalıştırmada çıktı kısadır:
✓ largest-contentful-paint: 2210 ≤ 2500
✓ cumulative-layout-shift: 0.04 ≤ 0.1
Gereksiz ayrıntı üretmez; hangi metriğin geçip hangisinin kaldığını anında görürsünüz. lhci assert --config=lighthouserc.js şeklinde çalıştırıldığında assert adımı önceden kaydedilmiş sonuçları okur. Bu, collect ve assert'i bağımsız CI adımları olarak ayırmanıza izin verir; bazı pipeline yapılarında sunucuyu ayrı bir adımda başlatmak ve durdurmak gerekir.
GitHub Actions entegrasyonu: PR'da zorunlu kapı oluşturmak
Lighthouse CI'ı GitHub Actions'a bağlamak için resmi action veya doğrudan CLI komutları kullanılır. CLI yoluyla tam kontrol genellikle daha temizdir. Temel bir workflow dosyası:
name: Lighthouse CI
on:
pull_request:
branches: [main]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Node kurulumu
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Bağımlılıkları yükle
run: npm ci
- name: Uygulamayı derle
run: npm run build
- name: Sunucuyu başlat
run: npm run start &
env:
PORT: 3000
- name: Sunucunun hazır olmasını bekle
run: npx wait-on http://localhost:3000 --timeout 60000
- name: Lighthouse CI çalıştır
run: npx lhci autorun
env:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
wait-on adımı atlanamazlar. Sunucu tam hazır olmadan Lighthouse başlarsa ilk istekler zaman aşımına uğrar veya hatalı düşük sonuç üretir. npm run start & background'da çalışır; sonraki adımlar sunucunun hazır olmadığı anda tetiklenebilir. Bu adım o riski ortadan kaldırır.
LHCI_GITHUB_APP_TOKEN opsiyoneldir. Tanımlandığında PR'ın commit durumuna Lighthouse sonucu eklenir; tanımlanmadığında sadece CI adımı başarılı veya başarısız olur. Bu workflow'u branch protection kurallarına eklemek, Lighthouse başarısız olduğunda merge'i otomatik olarak engeller. Settings üzerinden Branch protection rules altında "Require status checks to pass before merging" seçeneğine lighthouse job adını eklersiniz.
Depo yapısına göre URL stratejisi: neyi, nereden test etmeli
lighthouserc.js içindeki url listesi hangi sayfaların test edileceğini belirler. Tek bir anasayfa yeterli değildir; LCP regresyonları çoğunlukla ürün detay veya kategori sayfalarında yaşanır. Birden fazla URL tanımlayabilirsiniz:
collect: {
url: [
'http://localhost:3000/',
'http://localhost:3000/urunler',
'http://localhost:3000/urunler/ornek-urun',
],
numberOfRuns: 3,
},
Her URL için assert ayrı ayrı çalışır. Anasayfa geçse bile ürün sayfası başarısız olursa build durur. Statik site üreteçleri kullanıyorsanız Lighthouse CI kendi static server'ını başlatabilir:
collect: {
staticDistDir: './dist',
url: ['/', '/blog/', '/hakkinda/'],
numberOfRuns: 3,
},
staticDistDir tanımlıyken ayrı sunucu başlatmanıza gerek kalmaz; Lighthouse CI dizini doğrudan sunar. Bu, SSG projeleri için çok daha temiz bir yaklaşımdır. Next.js veya Nuxt gibi SSR çerçeveleri için staticDistDir kullanılamaz; sunucuyu kendiniz başlatmalısınız. Preview ortamı üretiliyorsa (Vercel, Netlify gibi) CI içinde sunucu başlatmak yerine preview URL'ini doğrudan kullanabilirsiniz, ama her PR için ayrı bir deploy adımı gerektirir.
Kararsız ortamlar ve yanlış pozitifler: gürültüyü azaltmak
CI ortamında Lighthouse çalıştırmak, gerçek kullanıcı deneyimini değil laboratuvar koşullarını ölçer. GitHub Actions runner'ları paylaşımlı altyapıdır; aynı commit iki farklı çalıştırmada 200 ms farklı TBT üretebilir.
numberOfRuns değerini 3'ten 5'e çıkarmak ortalama varyansı düşürür, ama CI süresini uzatır. Önemli metrikler için 5 run iyi bir seçimdir. Eşikleri gerçekçi tutmak şarttır; yüklü bir runner'da lab ortamında LCP için 2500 ms eşiği teknik olarak makul sayfaları bile bloklayabilir. Eşiği ilk iki haftada gözlemleyip ardından ayarlamak, sıfırdan doğru değeri tahmin etmeye çalışmaktan daha güvenilirdir.
assert konfigürasyonunda aggregationMethod kullanabilirsiniz:
'largest-contentful-paint': ['error', {
maxNumericValue: 2500,
aggregationMethod: 'pessimistic',
}],
pessimistic en kötü çalıştırmayı kullanır, median (varsayılan) ortancayı alır. pessimistic aşırı kırılgandır; küçük bir ağ dalgalanması build'i durdurur. Üç run ile median dengeli sonuç verir. Çevre değişkenlerine bağlı özellikler, özellikle üçüncü taraf scriptler, CI ortamında devre dışı bırakılabilirse Lighthouse sonuçları çok daha kararlı olur. TBT'deki dalgalanmanın büyük kısmı çoğu zaman bu scriptlerden kaynaklanır.
Eşik kalibrasyonu: çok sıkı veya çok gevşek ayarın bedeli
Eşiği çok sıkı tutmak, her PR'da başarısız build üretir ve ekip uyarıları görmezden gelmeye başlar. Çok gevşek tutmak ise zaten bozuk bir sayfayı geçirmeye devam eder. Her ikisi de işe yaramaz bir kapı kurar.
Başlangıç kalibrasyonu için şu sıra işe yarar: önce mevcut production sayfalarınızı aynı Lighthouse CI konfigürasyonuyla çalıştırın, median değerleri not edin, ardından bu değerlerin yüzde 10-15 üstüne eşik koyun. Mevcut durumu geçen ama anlamlı bir kötüleşmeyi yakalayan bir kapı sağlar.
LCP için maxNumericValue: 2500 Core Web Vitals sınırına denk gelir; ama bu değer gerçek kullanıcı verisiyle (RUM) karşılaştırılmadan koyulmamalıdır. Lab ile alan arasında çoğu durumda 20-30 yüzde sapma vardır; lab değeri 2,5 saniyeyse gerçek P75 çok daha yüksek olabilir. CLS ise lab ortamında genellikle düşük çıkar; kullanıcı etkileşimi gerektiren layout shift'leri lab ölçümüne girmez. Bu metriği lab'da geçip alan verisinde başarısız görmek normaldir.
INP bu kategoride ayrı durur. Gerçek kullanıcı etkileşimi gerektirdiğinden Lighthouse'un lab modunda INP ölçümü güvenilir değildir. INP için lab eşiği koymak yerine RUM tabanlı izleme tercih edilir; buraya error koymak genellikle anlamsız başarısızlıklara yol açar.
Performans kapısı tek başına yeterli değildir; pipeline'daki kapı yanlış ortam koşullarını, gevşek eşikleri veya geçici ağ dalgalanmalarını gizlerse, sessizce geçerli olmayan değerlere alışılır. Lighthouse CI'ın ürettiği trend verisini düzenli aralıklarla gözden geçirmek, eşiklerin hâlâ anlamlı olup olmadığını kontrol etmek kapının değerini korur.
Regresyon yakalandığında ne yapılacağını önceden tanımlamak da o kadar önemlidir. Build durdu, şimdi ne olacak? İlgili geliştiriciye bildirim mi gidecek, PR sahibi mi inceleyecek, belirli eşiğin üstüne çıkan değerler için farklı bir kural mı işleyecek? Teknik kurulum bu soruların cevabını vermez; ekip içi anlaşma sağlanmadan performans kapısı sürtüşme artıran ama davranışı değiştirmeyen bir araç olarak kalır.
Lighthouse CI ve GitHub Actions kombinasyonu bu iş için yeterince düşük maliyetli, yeterince güvenilirdir. Sıfırdan kurmak birkaç saati alır; bakımı yıllık birkaç konfigürasyon güncellemesine sığar. Altyapının karmaşıklığı değil, eşiklerin gerçekçiliği ve ekibin sürece sahip çıkması uzun vadede fark yaratır.