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.
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.
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()
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:
- Nesne Modelini Oluşturma
- Uses An Excessive DOM Size
- Reduce the Scope and Complexity of Style Calculations
- Minimizing browser reflow
- DOM change breakpoints
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.
- performance.mark(). MDN web docs ↩
- Using the User Timing API. MDN web docs ↩
- Rob Dodson. (2016). Controlling Font Performance with font-display ↩
- Jeremy Wagner. (2018). Using Lighthouse To Improve Page Load Performance ↩
- Addy Osmani. (2017). JavaScript Start-up Performance ↩
- web.dev. (2019). Serve static assets with an efficient cache policy. ↩
- web.dev. (2019). Reduce JavaScript execution time ↩
- Ilya Grigorik. (2019). Critical Rendering Path ↩
- web.dev (2020). Eliminate render-blocking resources ↩
- Ilya Grigorik. (2019). Render Blocking CSS ↩
- Website Performance Optimization. Udacity ↩
- web.dev. (2019). Serve images in next-gen formats ↩