Google Page Speed Optimizasyonu

PageSpeed Insight ile geliştiricilerin web siteleri ve web uygulamaları için sayfa bazında performans analizi yapabildiğinden bahsetmiştim.

AA

Bilindiği üzere, raporlarda pek çok metrik ve değerlendirmeler neticesinde hız optimizasyon önerileri çeşitli başlıklar altında sunulmakta ve teknik bazı ifadelere yer verilmekte. Bu yazıda, konunun devamı niteliğinde, sayfa raporlarında karşımıza çıkan hatalara, uyarılara ve bunların nasıl çözüme kavuşturulabileceğine değineceğim.

User Timing Marks and Measures

Kullanıcı zamanlama işaretleri ve ölçüleri ile (User Timing API) web sayfasının ve/veya uygulamanın JavaScript performansını ölçebiliriz. Bu ölçümdeki temel fikir, script’lerin hangi bölümlerinin optimize edilmesinin gerektiğini görmektir. API’nin denetim aşamasında, JavaScript değerlendirmelerine Chrome DevTools Timeline Recordings (Zaman Çizelgesi Kayıtları) üzerinden ulaşabiliriz.

Konuyla ilgili olarak ayrıca şu kaynaklar da incelenebilir:

Kullanıcı zamanlamasını web sitemizde / uygulamamızda nasıl kullanabileceğimize bir göz atalım. İlk aşamada, performance.mark() ile CSS dosyalarının işleniş sürecine ve sayfanın yüklenme sürecinde ne kadar etkili olduklarına bakalım.

User Timing

Bunun için, <head>...</head> etiketleri arasında yer alan css tanımlarının hemen ardından ilgili fonksiyonumuz1 ile zamanlamayı takip edelim2. Örnek için bulma css framework taslağı kullanacağım.

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Hello Bulma!</title>
  <script>
    performance.mark("CSS-start");
  </script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css" />
  <script>
    performance.mark("CSS-end");
    console.log(performance.getEntriesByType("mark"));
    performance.clearMarks();
  </script>
  <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
</head>

<body>
  <section class="section">
    <div class="container">
      <h1 class="title">
        Hello World
      </h1>
      <p class="subtitle">My first website with <strong>Bulma</strong>!</p>
    </div>
  </section>
</body></html>

Örnek içerisinde, performance.mark() ile işaretlenmiş alanları görebilirsiniz. Chrome DevTools > Console ile zaman etiketleri arasındaki ilişkiyi name ve startTime ile görebilir ve dosya yüklenme sürelerini bu bilgiler (ayrıca Chrome DevTools > Performance) ışığında optimize edebilirsiniz.

performance.mark()

performance.mark() ile marking işlemini görseller, iframe’ler, script’ler gibi pek çok kaynak için gerçekleştirebilirsiniz.

<script>
  performance.mark("Image-start");
</script>
<img src="https://cdn.sstatic.net/Img/unified/sprites.svg" />
<script>
  performance.mark("Image-end");
  console.log(performance.getEntriesByType("mark"));
</script>

Bu işlemi JavaScript dosyası için de tekrarlayabiliriz.

<script>
  performance.mark("JavaScript-start");
</script>
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<script>
  performance.mark("JavaScript-end");
  console.log(performance.getEntriesByType("mark"));
  performance.clearMarks();
</script>

performance.mark() web uygulamasının / sitesinin hızını veya PageSpeed puanını etkilemez.

Controlling Font Performance

Web yazı tipleri yüklenirken web sayfasını / uygulamayı görüntülenen ziyaretçinin sayfadaki metni görebilmesini sağlamak için yazı tipi görüntüleme CSS özelliğinden yararlanabiliriz3. Bu amaçla, font tanımına font-display: auto; ifadesini eklememiz gerekir.

@font-face {
  font-family: '...';
  font-display: auto;
}

Main Thread Work Breakdown

Ana iş parçacığı CSS (Style & Layout) ve JS (Script Evaluation) süreçlerini kapsar ve bu süreç mümkün olan en az zaman dilimine indirilmelidir4. JavaScript’in ayrıştırılması, derleme ve yürütme için harcanan zamanı kısaltma seçenekleri için modern geliştirme araçları (gulp, grunt, webpack, vb.) değerlendirilebilir5.

Cache policy on static assets

Uzun önbellek ömrü, sayfanızın tekrar ziyaret edilmesi durumunda sayfanın görüntülenme sürecini hızlandırabilir6. Bu nedenle önbellek kullanımı sayfa bazında güncelleme sıklığı göz önünde bulundurularak yönetilmelidir. Aşağıda 1 yıl (31557600 = 60 saniye * 60 dakika * 24 saat * 365.25 gün) için tanımlanmış bir ömür görülmektedir.

Cache-Control: max-age=31557600

JavaScript Boot-up Time

JavaScript yürütme süresi ayrıştırma, derleme ve yürütme için harcanan zamanı ifade eder. Bu süre mümkün olduğu kadar kısa tutulmalı ve sayfa en kısa sürece kullanıcı etkinliklerini anlayacak (time to interactive) aşamaya ulaşmalıdır7. Daha küçük JS yükleri ile bu süreç optimize edilebilir.

  • Ziyaretçilere sadece ihtiyaç duydukları etkileşimleri sunun,
  • JavaScript dosyalarını küçültün, gereksiz boşlukları ve açıklamaları kaldırın,
  • JavaScript yalınlaştırın ve sıkıştırın,
  • JavaScript kodunu önbelleğe alın.

Ana iş parçacığı başlığında da bahsi geçen modern geliştirme araçları kullanarak bu süreci otomatize edebiliriz.

Excessive DOM Size

Tarayıcının sayfayı oluşturabilmesi için önce DOM ve CSSOM ağaçlarını oluşturması gerekir. Sonuç olarak, HTML ve CSS’yi tarayıcıya mümkün olduğunca hızlı bir şekilde sağladığımızdan emin olmalıyız. Aşırı büyük bir DOM boyutu / derinliği sayfanın oluşma ve etkileşime geçme süreçlerini engeller. Tarayıcı mühendisleri bir sayfanın 1.500’den az DOM düğümü (node) içermesini, en fazla 32 öğe derinliğine sahip olmasını ve ana düğümsüz (parent node) 60’tan fazla alt düğüm (child node) olmamasını önerirler.

Konuyla ilgili olarak ayrıca şu kaynaklar da incelenebilir:

Critical Request Chains

Critical Request Chain, Critical Rendering Path (CRP) optimizasyon stratejisine ait bir konsepttir8. Amaç, kullanıcının bir sayfada gerçekleştirmek istediği birincil eylemle ilgili içeriği öncelikli hale getirmek ve bu içeriğin görüntülenmesini sağlamaktır. Kritik isteklerin derinliğini en aza indirilmesi ile gereksiz isteklerin gerçekleştirilmesini beklemek yerine önceliklendirmeyi gerekli kaynaklara aktarabiliriz.

Initial navigation
|---lighthouse/ (developers.google.com)
    |---/css (fonts.googleapis.com) - 1058.34ms, 72.80KB
    |---css/devsite-googler-buttons.css (developers.google.com) - 1147.25ms, 70.77KB
    |---jsi18n/ (developers.google.com) - 1155.12ms, 71.20KB
    |---css/devsite-google-blue.css (developers.google.com) - 2034.57ms, 85.83KB
    |---2.2.0/jquery.min.js (ajax.googleapis.com) - 2699.55ms, 99.92KB
    |---contributors/kaycebasques.jpg (developers.google.com) - 2841.54ms, 84.74KB
    |---MC30SXJEli4/photo.jpg (lh3.googleusercontent.com) - 3200.39ms, 73.59KB

Bu amaçla, sayfa yüklemesini iyileştirmek için zincir uzunluğunu azaltma, kaynakların indirme boyutunu küçültme veya gereksiz kaynakların indirilmesini erteleme seçenekleri değerlendirilebilir. DNS-Prefetch, Prefetch, Preconnect ve Prerender

Render-Blocking Resources

Hem HTML hem de CSS oluşturmayı engelleyen kaynaklardır ve bu kaynaklar sayfadaki first paint sürecini olumsuz etkilemektedirler9. Kritik JS/CSS’yi satır içinde yayınlama ve kritik olmayan tüm JS ve stilleri erteleme seçeneği10 ile bu süreç kontrol altına alınabilir. Unutmamak gerekir ki, hızlı sayfa yüklemeleri daha yüksek kullanıcı etkileşimi, daha fazla sayfa görüntüleme ve daha iyi dönüşüm sağlar.

Lighthouse üç tür engelleme kaynağı tanımlar.

  • <script> etiketi için:
    • <head> etiketi içerisinde mi?
    • Erteleme (defer) özelliği (attribute) tanımlı mı?
    • Asenkron (async) özelliği (attribute) tanımlı mı?
    • <link rel=”stylesheet”> etiketi için:
    • Devre dışı (disabled) bırakılmış bir özellik var mı? Bu özellik mevcut olduğunda, bazı tarayıcılar stil dosyasını işleme almaz. Unutmadan, bu özellik tüm tarayıcılar tarafından desteklenmemektedir.
    • Web sayfasını / uygulamayı görüntüleyen kullanıcının cihazıyla eşleşen bir medya (media) özelliği mevcut mu?
  • <link rel=”import”> etiketi için:
    • Asenkron (async) özelliği (attribute) tanımlı mı?

Kritik olmayan HTML içe aktarmaları (import) için asenkron özelliğinden (async attribute) faydalanabiliriz. Hatta, genel bir kural olarak, HTML import işlemlerinde mümkün olduğunca async kullanılmalıdır. Ayrıca, <head> etiketi içerisinde bulunan JavaScript kodları eğer zorunluluk yok ise ana işlemlerden sonra çağırılabilir. CSS dosyaları ise alt bölümlerde kullanıldığında hatalara sebep olur. Bu nedenle <head> içerisinden çağırmamız gerekir. Ancak, satır içi (inline) kullanım ile bu süreç optimize edilebilir.

Offscreen Images

Ekran dışı görüntüler (offscreen images), ekranın altında kalan (below the fold) görsellerdir. Kullanıcılar bir sayfa yüklendiğinde ekran dışında kalan görüntüleri görmediklerinden, ekran dışı görüntüleri ilk sayfa yüklemesinin bir parçası olarak indirmemiz gerekmez. Diğer bir deyişle, ekran dışı görüntülerin yüklenmesini erteleyerek (lazy-load) sayfa yüklenme süresini ve etkileşimli hale gelme süresini (time to interactive) kısaltabiliriz.

Ekran dışı görüntüleri optimize etmek ve yüklenme süresini kısaltmak amacıyla, ilk istek sırasında yalnızca ekranın üstündeki görüntülerin indirmesini sağlayabiliriz. Ayrıca, bu stratejiyi JS, HTML, CSS ve diğer kaynaklar için de uygulamak mümkün. Konuyla ilgili daha detaylı bilgi almak ve eksikliklerinizi gidermek için Website Performance Optimization by Google11 başlıklı ücretsiz kursa katılabilirsiniz.

Optimized Images & Next-Gen Formats

JPEG 2000, JPEG XR ve WebP, eski JPEG ve PNG benzerlerine kıyasla üstün sıkıştırma ve kalite özelliklerine sahip görüntü formatlarıdır12. Resimlerinizi JPEG veya PNG yerine bu formatlarda kodlamak, daha hızlı yüklenecekleri ve daha az hücresel veri tüketecekleri anlamına gelir. WebP, Chrome ve Opera tarafından desteklenmektedir ve web’deki görüntüler için daha iyi kalitede ve kayıpsız sıkıştırma sağlar.

Son Olarak

Single Page App (SPA) ve Vue örneklerinde, yukarıda bahsi geçen konuları da örneklendirme sürecine dahil edecek, tamamlanan örnekleri ayrıca bu başlık altında listelemeye çalışacağım.