Kapak tasarımı Elif Yardımcı

Server-Side Rendering Evrimi: Streaming SSR ile TTFB ve TTI Sınırlarını Kaldırın

Oguzhan Sofuoglu
Published in
7 min readNov 3, 2023

--

Herkese selam!

Son yıllarda, web geliştirme dünyası, Single Page Application (SPA)’ların yaygın kabulünü takıben, çeşitli server odaklı işleme modellerinin gelişimini gördü. Bu makalede, en popüler rendering patternlerden biri olan Server Side Rendering’in (SSR) bazı dezavantajlarını ortadan kaldırmayı amaçlayan Streaming SSR’ı konuşacağız.

Bu rendering patternleri daha iyi anlamak için genellikle TTFB, TTI, FPC veya CLS gibi Web Vitals metriklerine başvuracağız. Konuyu daha iyi anlamak için aşağıdaki linkten bu metrikleri tekrar inceleyebilirsiniz: https://web.dev/articles/user-centric-performance-metrics

Peki, Streaming SSR tam olarak nedir ve web geliştirme alanına bir yenilik getiriyor? Hadi, bu heyecan verici yeni rendering pattern hakkında keşfe çıkalım.

Server-Side Rendering (SSR) nedir?

Server Side Rendering, web sayfalarının öncelikle sunucuda render edildiği ve ardından istemciye (browser) gönderildiği popüler rendering patternlerden biridir. Client Side Rendering’in (CSR) aksine, burada çoğu rendering işi, tarayıcı yerine sunucuda gerçekleştirilir.

SSR’in calisma mekanizmasi [Source]

Peki, SSR nasıl çalışır?

  1. Tarayıcıdan sunucuya istek atılır.
  2. Serverda bir HTML oluşturulur. Bu server her istekte yeni bir HTML oluşturma yeteneğine sahiptir. Oluşturulan HTML tarayıcıya gönderilir. (TTFB anı)
  3. Tarayıcı gelen bu HTML’i parse edip renderlar. Bu noktada, kullanıcıya gösterilebilecek bir kullanıcı arayüzümüz var, ancak kullanıcıyla etkileşimde bulunabilmesi için JavaScript’e ihtiyacımız var.
  4. Tarayıcı, gerekli JavaScript paketini almak için bir istek gönderir ve onu indirir.
  5. Tarayıcı, JavaScript’i yürütür ve hydration yapar. (TTI anı)
SSR icin Web Vital Metrikleri [Source]

Server-Side Rendering’in bazı temel faydaları şunlar olarak sıralanabilir:

  1. Geliştirilmiş SEO: Arama motorları, başlangıç sayfasının tamamen sunucuda render edildiği için içeriği kolayca tarayabilir ve dizine ekleyebilir. Bu, Client Side Rendering’e (CSR) kıyasla daha iyi arama motoru sıralamalarına imkan verir.
  2. Erişilebilirlik: Server Side Rendering, başlangıçtaki HTML içeriğinin hemen kullanılabilir olmasından dolayı erişilebilirliği artırabilir. Bu, ekran okuyucularının ve diğer yardımcı teknolojilerin içeriği yorumlamasını daha kolay hale getirir.
  3. Daha İyi Kullanıcı Deneyimi (UX): Kullanıcılar tamamen render edilmiş bir sayfa aldıkları için içeriği daha hızlı kullanmaya başlayabilirler, bu da daha iyi bir kullanıcı deneyimi sağlar. Ayrıca Cumulative Layout Shift (CLS) problemlerinin de önüne geçerek, kullanıcıya yüklendiği ilk andan itibaren stabil bir UI sağlar.

Peki SSR ile ilgili her şey çok mu iyi? Ne yazık ki hayır. Her rendering patternde oldugu gibi, SSR’da kendi avantajları ve dezavantajlarına sahiptir. Bu yazıda iki potansiyel dezavantajını inceleyeceğiz; İlk Bekleme Süresi, bu TTFB (Time to First Byte) metriği ile ilişkilidir ve Etkileşim Gecikmesi, bu da TTI ( Time to Interactive) metriği ile ilişkilidir.

TTFB — Ilk Bekleme Suresi: SSR’ın dezavantajlarından biri, kullanıcının tarayıcısına ilk byte’in ulaşması için gereken zamanı temsil eden TTFB’nin uzamasıdır. Bu gecikme, SSR’ın tüm HTML’i sunucuda render etme sürecini içerdiği için ortaya çıkar. Tüm HTML’i renderlamak, o sayfa için gerekli tüm veri isteklerini beklemeyi ve sayfayı oluşturan tüm logical kodların yürütülmesini gerektirir. Sonuç olarak, kullanıcılar bu yükleme süreci sırasında boş bir ekran deneyimleyebilir, bu da kullanıcı deneyimini olumsuz yönde etkileyebilir.

TTI — Etkileşim Gecikmesi: SSR ile TTI anı gecikebilir. Sunucuda renderlanan HTML, TTFB anı sonrasında görünür olabilirken, tarayıcı bu sayfayı etkileşimli hale getirebilmek için JS Bundle’ı indirir ve yürütürken etkileşim ertelenir. Bu gecikme genel kullanıcı deneyimini yine kötü etkileyebilir.

Bu iki olumsuz etkiyi hafifletmek için React 18 ile hayatımıza yeni bir rendering pattern girdi: Streaming SSR.

What is the Streaming SSR?

Streaming SSR, Server Side Render (SSR) kullanırken TTFB ve TTI metriklerimizi iyileştirmeye yarayan yeni bir yöntemdir. Streaming SSR’in arkasındaki mantık, veriyi parça parça ve sürekli olarak aktarmamızı sağlayan Node Streams adını verdiğimiz bir kavrama dayanır.

Standart SSR’da, sayfamızı oluşturan tüm HTML’i sunucuda renderlamak ve ardından bu HTML için gerekli olan tüm Bundle JS’ı istemciye aktarmak, önceki bölümde tartışıldığı gibi TTFB ve TTI dezavantajlarını ortaya çıkarıyordu. Streaming SSR, sayfada bulunan her bileşeni (component) ayrı ayrı renderleyarak ve component bazında JS bundlelar oluşturarak bir çözüm sunar. Bu, sayfada göstereceğimiz her şeyi parça parça (her bir parçayachunks diyoruz) istemciye aktarmamıza olanak tanır.

Left: SSR | Right: Streaming SSR [Source]

Streaming SSR mekanizmasını adım adım inceleyerek nasıl çalıştığını anlamaya çalışalım:

  1. İstemciden sunucuya bir istek gönderilir.
  2. Artık sunucu temel bir HTML dosyası ile birlikte veri transferi için node streams’a izin veren bir yapıyı tarayıcıya döndürür. (Bu temel HTML dosyası, SEO için gerekli veriyi içerir, bu nedenle SEO dezavantajımız olmaz.)
  3. İstemci bu HTML’yi alır ve SSR’da olduğu gibi aynı şekilde işler. Node Streaming de bu noktada başlar.
  4. Sunucu, renderi tamamlanan bileşenlerinin HTML ve JS Bundle’ını parçalar halinde browsera aktarır.
  5. Tarayıcı bu parçaları işler ve hydrate ederek kullanıma hazır hale getirir.
Web Vital metrics for Streaming SSR [Source]

Bu yaklaşımın en dikkat çeken faydalarından biri, sunucu tarafında render edilen içeriğin tamamlanmasını beklemeye gerek olmamasıdır. Sonuç olarak, Time To First Byte (TTFB) önemli ölçüde azalır.

Web Vitals Comparision for SSR vs Streaming SSR [Source]

Başka dikkate değer bir avantaj, hydration süreciyle ilgilidir. Standart Server Side Rendering (SSR) kullaniminda, sayfadaki tüm öğelere ait kodu içeren büyük bir Js Bundle’in çalıştırılması gerekiyordu. Ancak yeni yaklaşım ile yalnızca belirli bir bölüm (chunk) için gereken kodu çalıştırabiliriz, bu da Time to Interactive (TTI) açısından büyük bir iyileşmeye yol açar.

Sonuç olarak, ilk chunk’a ait hydration işlemi tamamlandığında, Time to Interactive (TTI) gerceklesmis olur. Bu, tarayıcının bu andan itibaren etkileşimli hale geldiği anlamına gelir.

NextJs 13 ile Streaming SSR Implementasyonu

Teorik kısmı tamamladık. Şimdi bu yeni patterni Next.js ile nasıl uygulayacağımızı öğrenelim.

Next.js 13 ile data-fetching yöntemleri önceki sürümlere gore farklılaştı. Artık varsayılan olarak gelen Server Components’ler ile birlikte Component içinde herhangi bir effect hook’u veya getServerSideProps gibi sunucu tarafı özellikleri kullanmadan doğrudan veri çekebiliyoruz.

Örneğin, aşağıda standart SSR kullanan bir sayfa yapısı görebilirsiniz:

export default async function Page() {

/**
* Daha dusuk TTFB icin, sayfada gereken tum
* istekler paralellestirilmistir.
*/
const productsPromise = getProducts();
const personsPromise = getPersons();
const plansPromise = getPlans();

const [productData, personsData, plansData] = await Promise.allSettled([
productsPromise,
personsPromise,
plansPromise
]);

return (
<div>
<Products data={productData} />
<Persons data={personsData} />
<Plans data={plansData} />
</div>
);
}

Bu yapının içinde, kullanıcıya sayfayı göstermeden önce tüm istekler tamamlanmalı ve ardından bu elde edilen veriler kullanarak sayfadaki tüm bileşenler sunucu tarafında oluşturulmalıdır. Sonrasında, bu tüm işlemlerin sonucu olarak oluşturulan HTML ve JS tarayıcıya gönderilir.

Peki, Streaming SSR nasıl uygulanır?

  1. Component Bazlı Data-Fetching

Her component kendi isteklerini atmaktan sorumlu olmalıdır. Streaming SSR’da temel fikir, bileşenlerin render mekanizmasını ayırmak ve herhangi bir bileşenin kendi verileri hazır olduğunda kendi başına gösterilebilmesini sağlamaktır. Bu nedenle, her bileşen için veri isteklerimizi ayırmaya başlamamız gerekiyor.

2. React Suspense

Component’in, Streaming SSR ile render edilebileceğini React’e bildirmek için Suspense ile sarmalamamız gerekiyor.

Suspense zaten hali hazirda Code Splitting için bildiğimiz ve kullandığımız bir yapıydı. Artık React 18 ile birlikte , Suspense SSR Streaming kullanılan Component oluşturmamıza imkan sağlıyor. Daha fazla detay için React dokümantasyonuna bakabilirsiniz.

Benzer sayfanın SSR Streaming implementasyonu görelim:

export default function Page() {
return (
<div>
<Suspense fallback={<Skeleton/>}>
<Persons />
</Suspense>
<Suspense fallback={<Skeleton/>}>
<Plans />
</Suspense>
<Suspense fallback={<Skeleton/>}>
<Products />
</Suspense>
</div>
);
}

Streaming SSR’da, Suspense ile sarılan her bileşen, kendi istekleri tamamlandıktan sonra kendi render işlemini tamamlar ve ardından tarayıcıya aktarılır. Bu, standart bir SSR örneğinde olduğu gibi tüm isteklerin tamamlanmasını ve tüm sayfa render işleminin tamamlanmasını beklememize gerek olmadığı anlamına gelir. Ayrıca, ilk hydration işleminden sonra (yani TTI anı), tarayıcı kullanıcı etkileşimine hazır hale gelir. Bu nedenle, kullanıcı hala render işlemi devam eden diğer bileşenleri beklemek zorunda kalmaz.

Streaming SSR’ın başka bir avantajı da, bunu sayfanızdaki herhangi bir alt bileşen (child component) için de kullanabilmenizdir. Bu konuda bir sınırlama yoktur. Bu nedenle, iç içe geçmiş bileşenlerin en altındaki bileşenler de dahil olmak üzere istediginiz bileşeni Suspense ile sarıp streaming’in faydalarından yararlanabilirsiniz. Bu sayede sayfanın oluşma süresini ve kullanıcının sayfayla etkileşiminin kesilmesinin önüne geçebilirsiniz.

Bunlara ek olarak, Next.js 13 Streaming SSR’a dayanan bir Loading UI özelliği sunuyor. Bu, Time to First Byte (TTFB) anına kadar sayfanızda içerik alanında skeleton, spinner vb. istediğiniz şeyleri göstererek kullanıcı deneyimini geliştirmeye yardımcı olur. Bu sayede kullanıcılar boş bir sayfa yerine layout ile birlikte tanımladığınız placeholder’i görebilir. Daha fazla detay için linki inceleyebilirsiniz.

Bütün bu konuştuklarımızı daha iyi anlamak için Standart SSR, SSR + Loading UI ve Streaming SSR yöntemlerini içeren küçük bir demo hazırladım.

Live demo’yu buradan inceleyebilir, kaynak kodlarına buradan ulaşabilirsiniz.

Sonuç

Bu makalede, web geliştirmenin sürekli değişen dünyasında ortaya çıkan heyecan verici yeni bir rendering pattern olan Streaming SSR’ı inceledik.

Streaming SSR, geleneksel Server Side Rendering (SSR) ile uzun zamandır ilişkilendirilen Time to First Byte (TTFB) ve Time to İnteractive (TTI) gibi bazı sorunları çözmek için umut verici bir çözüm olarak karşımıza çıkıyor. Ayrıca, Streming SSR, performansı optimize etmek için kullandığımız CSR + SSR gibi hybrid yapılar için yeni seçeneklerin de önünü açıyor. Bu gelişmeler gerçekten heyecan verici.

Biz ÇSTech olarak, daha iyi bir Kullanıcı Deneyimi (UX) ve Geliştirici Deneyimi (DX) için Streaming SSR gibi yenilikleri yakından takip ediyor ve mevcut uygulamalarımıza uygulamaya çalışıyoruz.

Sorularınız veya önerileriniz için aşağıdaki adreslerden bana ulaşabilirsiniz.

Tekrar görüşmek üzere, hoşça kalın.

Oğuzhan Sofuoğlu

Frontend Developer @ÇSTech

Github | Linkedin | Personal Website

--

--