Proje: Okul Platform · Hub: Okul Platform — Decisions

Karar

resources/views/responsive/profiling/test/index.blade.php’de wizard skeleton’ı statik ilk soru markup’ı ile değiştirildi. Ayrıca profiling.js için <link rel="preload" as="script"> eklendi.

Problem

Önceki PR (2026-05-11-responsive-tracking-defer-and-css-inline) tracking defer + CSS inline ile render-blocking ve TBT düşürdü, ama LCP hâlâ yüksek (~8.6s).

Root cause — LCP candidate shift:

t=3.2s   FCP: h1 hero paint → LCP candidate = h1 (~360×100px)
t=8.6s   Alpine init → ready=true → x-cloak kalkar → wizard kart paint
         → LCP candidate = wizard kart (text-rich, 360×400px) ← FİNAL LCP

Skeleton text içermediği için LCP eligible değildi (LCP sadece img/text/bg-image elementlerini sayar). Wizard kartının içindeki gerçek soru text’i yalnızca <template x-for="(q, idx) in questions"> Alpine boot’tan sonra expand olurdu → LCP wizard kartının paint anına kadar gecikiyordu.

Çözüm

İlk soruyu Blade’de statik HTML olarak render et. Alpine boot beklemeden FCP anında gerçek içerik paint olur:

  • LCP element = h1 hero VEYA statik wizard text bloğu (her ikisi de t=FCP’de paint)
  • Alpine boot olunca: x-show="!ready" statik bloku gizler, x-show="ready" x-cloak dinamik wizard’ı gösterir
  • Statik ve dinamik versiyon görsel olarak identical → no flicker, no CLS

pointer-events: none ile statik blok’ta tıklamalar engellenir (Alpine state’e propagate olmaz, kayıp tıklama riski yok).

Ek olarak <link rel="preload" as="script"> ile profiling.js download’u HTML parse esnasında başlar (eskiden body sonu defer → daha geç başlıyordu). ~300-500ms erken hydrate.

Trade-off

Pros:

  • LCP 8.6s → ~3.5s beklentisi (FCP’ye kilitlenir)
  • CLS değişmez (static/dynamic identical sized)
  • Skeleton’a göre semantic değer artar (ilk soru SEO/SR için de görünür)

Cons:

  • Dual source of truth: scoring-data.js questions[0] değişirse Blade statik markup manuel güncellenmeli. Yorum satırı eklendi.
  • Statik ve dinamik wizard kısa süreli (Alpine boot sırasında) DOM’da aynı anda var → minimal SR re-announce ihtimali
  • HTML payload ~1KB artar

Alternatifler ve neden seçilmedi

  • Hero h1’i büyütüp LCP yapma — Tasarım kararı, brand impact, scoring belirsiz (text-22 → text-32 hâlâ wizard kartı geçemeyebilir)
  • Controller’dan @json($questions) ile inject — BE değişikliği gerektirir; CLAUDE.md “ALWAYS ask before BE changes”. Plus scoring-data.js’i PHP’ye port etmek ek bakım yükü
  • Alpine bundle code-split (sadece wizard component) — Build pipeline değişikliği (webpack entry restructure), team review gerekir; ayrı PR

Uygulanan dosyalar

  • resources/views/responsive/profiling/test/index.blade.php
    • Skeleton blok → statik ilk soru markup’ı
    • @section('head_extra') ile profiling.js preload

Etki kapsamı

Sadece egitim-yaklasimi-testi sayfası. Result/finder sayfalarında LCP başka faktörlere bağlı (sonuç render’ı async AJAX).

Related