Nextjs ile Server-side-rendering(SSR) ve client-site-rendering(CSR)’i keşfedelim.(Uygulama ile beraber)
Herkese merhaba React, VueJS ve Angular gibi Javascript frameworkleri popüler olduktan sonra client-side-rendering, server-side-rendering, prerender gibi kavramlarla sikca karsilasmaya basladik . Her ne kadar dökümanlar ile beraber bu işlemleri öğrenmeye çalışakta oldukça kafa karışıklığına yok açacak bir çok kavram ve sorun karşımıza çıkıyor.
Reac, VueJS ve Angular gibi js frameworklerin çalışma şekillerini söyle özetleyebiliriz.
Browser sunucuya bir istek yapar, sunucu yanit olarak bir .js dosyasi dondurur, tarayici da bu .js dosyasini yorumlayarak HTML+CSS’e donusturur ve sayfa kullanıcının ekranında gözükür.
Şimdi Client-Side Rendering kavramını bir örnek ile hep beraber incelemek için basit bir Nextjs uygulaması geliştirelim.
Tüm basit işlemleri bildiğinizi düşünerek basit bir anlatım yapacağım eğer bahsettiğim aşamaların kodlanmış hazır haline ulaşarak isterseniz repo ile çalışmaya başlayabilirsiniz.
https://github.com/kubilaybzk/nextjs_pokemon_app
Öncelikle eğer bu i
yarn create next-app nextjs_pokemon_app
komutu ile bir nextjs uygulaması geliştirelim.
Daha sonra index.js dosyası içini tamamen temizleyelim.
Bir adet useState ve useEffect hook oluşturalım.
const [pokemon,setPokemon]=useState([]);
Daha sonra UseEffect ile verileri çekelim.
useEffect(()=>{async function getPokemon(){const responce = await fetch ("https://jherr-pokemon.s3.us-west-1.amazonaws.com/index.json")setPokemon(await responce.json());console.log(pokemon)}getPokemon();},[])
Yukarıda gördüğünüz gibi api içinde bulunan bütün pokemonları çektik ve ekrana yansıttık Front end tasafı ile uğraşmamak için aşağıda bulunan js dosyasını kopyalayıp kullanabilirsiniz.
Styles klasörü içinde bulunan Home.module.scss dosyasına aşağıda bulunan kodları yapıştırarak hiç css ile uğraşmayalım.
Projemizi run alalım ve Sonucu hep beraber görelim.
Gördüğünüz gibi projemiz başarı ile çalıştı ve bütün pokemonlar ekranda gözüküyor :)
Şimdi her bir pokemon için bir detay sayfası yapalım .
Page klasöründe yeni bir klasör oluşturalım adını pokemon yapalım.
daha sonra altına [id].js ismi ile bir js dosyası oluşturalım .
Css uygulamak için styles kalsörünün altına Details.module.css dosyası oluşturalım
Gördüğünüz gibi artık her bir pokemon için basit bir detay sayfasınada sahip olduk.
Şimdi hep beraber Client-Side Rendering hakkında konuşalım.
Nedir bu Client-Side-Rendering: Çok ama çok basit bir anlatım ile web uygulamalarının tarayıcı üzerinden render edilmesi diyebiliriz. Yani kullanıcı bir web uygulaması için request yürürlüğe soktuğu zaman server kullanıcıya Html dosyası yada JavaScript dosyası yollar tarayıcı tarafından indirilen bu dosyalar hemen işleme alınır (yorumlanır) bu işlem sırasında kullanıcı ekranında yükleniyor veya sadece beyaz bir sayfa görebilir. (Bu geliştirilen uygulamaya göre değişir)
Bunun ıspatını söyle yapabiliriz . Öncelikle Bulbasaur ‘ın detay sayfasına girelim.
Şimdi öncelikle Chrome için sayfada herhangi bir boş alanda sağ tık yapalım ve sayfa kaynağını görüntüle diyelim yada klavyemizden CTRL+U kısayoluna basalım.
Kaynak kısmını incelemeye başlayalım.
Sayfada gördüğünüz gibi kaynak kısmında Bulbasaur hakkında hiçbir bilgi gözükmüyor bu oldukça normal çünkü biz client tarafında render aldık yani sayfa kullanıcının tarayıcısında oluştu.
Şimdi söyle bir şeyde deneyelim. İnternet hızımızı yavaşlatalım ve nasıl bir sonuç alacağız onu görelim.
Sayfamızda f12 kısayolu ile geliştirici konsolu açalım ve Network kısmından
slow 3G kısmını seçelim .
Şimdi Bulbasaur için açtığımız detay sayfasını yeniden yükleyelim (F5 atalım :) )
Gördüğünüz gibi sayfamız oldukça yavaş yükleniyor bu yüklenme sırasında kullanıcı sadece beyaz bir ekran görüyor bu yukarıda bahsettiğimiz beyaz ekran görme yada yükleniyor olarak ekranda bir sonucun gözükmesi durumundan sadece bir tanesi, biz uygulamamızda yükleniyor … gibi bir ekran oluşurmadık bundan dolayı kullanıcılar sadece beyaz ekran görecek.
Şu konuya da değinmek istiyorum request’in client tarafından alındığının bir başka ıspatınıda söyle yapılabilir tekrar geliştirici seçenekleri kısmında Network kısmına geçelim burada yaptığımız bütün ayarları geri alalım.
Ve http://localhost:3000/pokemon/1 sayfamızı refresh edelim. Burada gördüğünüz gibi API isteği sonucu 1.json isminde bir dosya gelmiş gözüküyor, bu ne anlama geliyor diye sorarsanız bu bize dataları client tarafında çağırdığımızı gösteriyor.
Ek olarak söyle bir bilgi vermek istiyorum projemizi build ettiğimiz zaman NextJS’nin oluşturduğu sayfaları söyle görebiliriz.
Oluşturulan sayfa sayısının ne kadar az olduğuna dikkat edin lütfen bu konuya ileride değineceğiz.
Client-Side Rendering repo :
https://github.com/kubilaybzk/next_render_types/tree/641539dd676ef774a14c6fb27a4d495915f05cf2
Server-Side Rendering
Şimdi Server-Side Rendering ile uygulamamızı kodlayalım.
Öncelikle index.js dosyamızı SSR ile geliştirelim ,yapmamız gereken ilk işlem state ve useEffectleri kaldırmak. Daha sonra SSR yapmak için getServerSideProps adında bir fonksiyon kullanacağız.
Kesinlikle ama kesinlikle getServerSideProps kullanırken export edilmesi ve asyn olan bir fonksiyon olduğunu unutmamız gerekiyor. Ek olarak bu fonksiyonun bir props return ettiğini de unutmamamız gerekiyor .
function Page({ data }) {
// Render data...
}
// This gets called on every requestexport async function getServerSideProps() { // Fetch data from external API
const res = await fetch(`https://.../data`)
const data = await res.json()
return { props: { data } } // Pass data to the page via props
}
export default Page
Yukarıda basit bir kullanımını görüyoruz. Şimdi kodumuza uygun olarak geliştirdiğimiz uygulamaya bu fonksiyonu entegre edelim ve sonucu inceleyelim.
Uygulamamızı kapatıp tekrar açalım (Konsol üzerinden CTRL+C yapıp kapatalım ve tekrar npm run dev yazarak uygulamamızı yeniden run edelim .)
Gördüğünüz gibi hiçbir değişiklik yok fakat sayfamızın kaynağını incelemek isteyelim. Yukarıda SSR olmadan geliştirdiğimiz index.js kaynak kodu ile SSR olarak geliştirdiğimiz index.js arasında bulunan farkı görüyorsunuz.
Şimdi ise [id].js ile devam edelim.
Burada fonksiyonumuza dikkat edersek {{params}} adından bir değişken almış bunun sebebi basitçe bizim sayfamızın statik olmaması [id].js olarak tanımlanmış olması .
Şimdi fark edeceğiniz üzere hiçbir değişiklik yok uygulamamızda fakat . Ivysaur ‘a tıklayıp detaylara bakalım .
Şimdi tekrar bu ekranda sağ tıklayalım ve kaynak kodlarını inceleyelim .
Görüdüğünüz gibi kaynak içine bütün datalar gelmiş . Yani uygulama client tarafınada değil server tarafında render olmuş ve biz sayfada herhangi bir pokemon için detay sayfasına gittiğimiz zaman burada gerekli olan tüm html dataları server tarafında oluşturulup bize yollandı.
Network kısmına bakalım .
Gördüğünüz gibi herhangi bir 1.json 2.json gibi bir dosya yok burada bu işlemin serverside tarafında olduğunun başka bir kanıtı.
Server Side Rendering işleminin genel olarak çalışma mantığı aşağıda bulunan diagram ile basitçe açıklayabiliriz. SSR ile beraber çok daha iyi seo desteği sunarız çünkü Google’ın botları web sitelerinde gezerken kaynak kodlarını incelerler eğer kaynak içinde ürünlerimiz hakkında bilgiler mevcut ise bu daha iyi bir seo deneyimi sağlar . Seo için her ne kadar iyi olsada server tarafından oldukça maliyetlidir (buradaki maliyer fiyat olarak değil .)
Şimdi getServerSideProps fonksiyonundan biraz daha bahsetmek istiyorum .
Burada bilmemiz gereken bir kaç önemli kısım var yukarıda da bahsettiğim gibi bu fonkisyon bir props return ediyor bu return eden props bizim sayfamızın ana main compenentine gelen bir props olarak tanımlamamız gerekiyor. Örnek uygulamamızda ;
export default function Details({ pokemon }) olarak yolladığımız gibi.
İkinci önemli nokta ise bu fonksiyonun bir async fonksiyon olduğu.
- Yalnızca sunucu tarafında çalışır ve hiçbir zaman tarayıcıda çalışmaz.
- Sadece page klasörü altında bulunan js jsx yada tsx dosyaları içine yazılır.
Tekrar Vercel üzerinden deploy edilmiş halini inceleyelim. Şimdi burada gördüğünüz gibi oluşan sayfa sayısı Client-Side-Rendering ile aynı.
Static-Site Generation
Tekrar Vercel üzerinden deploy edilmiş halini inceleyelim. Şimdi burada gördüğünüz gibi oluşan sayfa sayısı Server-Side-Rendering’den kat ve kat fazla api içinde bulunan 796 sayfa bunlar
pokemon/1
pokemon/2
pokemon/3
…
pokemon/796'ya kadar giden sayfalar otomatik olarak oluşturuldu.
Kısaca özetlemek gerekirse. Versel üzerinden build edilen sayfaların tek tek çıktıları bu şekilde.
Client-Side Rendering için ;
Kaynak dosyamız içinde hiçbir bilgi bulunmuyor.
Server-Side-Rendering için sayfamız :
Kaynak dosyamız içinde bilgiler mevcut.(CEO için çok uygun)
Static-Site Generation için ;
Kaynak dosyamız içinde bilgiler mevcut.(CEO için çok uygun)
Elimden geldiğince basit bir şekilde SSR ve CSR’ı anlatmaya çalıtştım umarım yardımcı olabilmişimdir .
Repo :
https://github.com/kubilaybzk/nextjs_pokemon_app
Commit edilen mesajlara göre adım adım kodları inceleyebilirsiniz.