Client Side Rendering
W dzisiejszym wpisie przyjrzymy się z bliska, jak wygląda cały proces od momentu wysłania Twojego żądania do wyświetlenia wyniku na ekranie użytkownika
Kiedyś to było
Dawno dawno temu w odległych Internetach strony i aplikacje były pisane między innymi w PHP. Miało to zasadnicze zalety w postaci dobrego SEO (pozycjonowanie w wynikach wyszukiwania) i szybkiego ładowania dużej ilości treści, ale również nie obyło się bez wielu wad.
Każde wysłanie formularza, pobranie dodatkowych danych czy nawet przejście na inną podstronę wymagało ponownego odświeżenia całej aplikacji. Takie zachowanie było spowodowane renderowaniem po stronie serwera bez hydracji (ożywienia statycznego HTML’a za pomocą JS’a). W wyniku tego przeglądarka jedyne co może zrobić to poprosić serwer o więcej danych i odświeżyć stronę, gdy już je otrzyma.
Te czasy na szczęście za nami, a obecna technologia przedstawia zupełnie inne podejścia do renderowania. Jednym z nich jest tytułowy bohater, czyli Client Side Rendering
Jego podstawowym wyróżnikiem jest to, że ciężar wyrenderowania treści spoczywa na urządzeniu klienta. Serwer, zamiast budować całego HTML’a, zwraca nam statyczne pliki i mówi "baw się dobrze". Cały UI zostaje stworzony od zera za pomocą kodu JavaScript. Aplikacje tworzone w ten sposób często nazywa się Single Page Application (SPA)
Proces krok po kroku
Wszystko, co musi się wydarzyć, jest widoczne na pierwszy rzut oka, więc przyjrzyjmy się całemu mechanizmowi z bliska:
- Użytkownik wysyła żądanie do serwera w celu pobrania strony. Może się to odbyć poprzez kliknięcie w link lub za pośrednictwem wyszukiwarki
- Serwer w odpowiedzi wysyła minimum potrzebnego HTML’a. Zawiera on tylko podstawową strukturę i ewentualnie jakiś loader oraz linki do zasobów (pliki CSS i JS) Przykład:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Client Side Rendering Example</title> <link rel='stylesheet' href='style.css'> <script defer src='script.js'></script> </head> <body> <div id='app'>Loading...</div> </body> </html>
- Następnie przeglądarka parsuje otrzymany HTML od góry do dołu. Napotykając na skrypty i linki, natychmiast je wykonuje lub odracza uruchomienie do czasu pełnego sparsowania HTML’a (atrybuty async i defer)
- Ostatnim krokiem jest zaaplikowanie pobranych arkuszy stylów oraz uruchomienie skryptów. Tym samym został zbudowany w pełni interaktywny i ostylowany interfejs użytkownika.
Po zaledwie 4 krokach użytkownik jest w stanie wchodzić w interakcje z witryną. Gdy wyślemy żądanie o więcej danych, zostaną pobrane i zaaplikowane do strony bez potrzeby jej odświeżania (dzięki JavaScript'owi i Fetch API)
Poniższa grafika podsumuje całą sekcję:
Nie ma renderowań idealnych
Tak jak wszystko CSR ma swoje wady i zalety. W wielu przypadkach będzie to świetny wybór, ale nie zawsze. Spójrz na krótkie zestawienie
Zalety
- Bardzo dobra interaktywność, gdy strona już raz się wyrenderuje. Po pierwszym nieco dłuższym ładowaniu aplikacja działa szybko i sprawnie odpowiada na akcje użytkownika.
- Wyraźna separacja. Kod backendowy jest odseparowany od kodu frontendowego. Można niezależnie skupić się na rozwoju UI lub API.
- Istnieje możliwość "doczytywania" danych na żądanie za pomocą Fetch API bez konieczności odświeżania strony.
- Do obsługi wystarczy nam bardzo prosty serwer hostujący jedynie statyczne pliki.
Wady
- Roboty indeksujące nie są w stanie sprawnie przeskanować strony, która generuje się po stronie klienta. Wpływa to bardzo negatywnie na SEO i pozycjonowanie w wynikach wyszukiwania
- Im większa aplikacja, tym większy jest finalny bundle (zmiksowane pliki JS i inne assety). Z tego powodu First Contentful Paint https://web.dev/articles/fcp i Time to Interaktive https://web.dev/articles/tti mogą być bardzo powolne
- Słabsze urządzenia (np. stare telefony) gorzej poradzą sobie z renderowaniem dużej ilości danych. W wyniku tego strona będzie generowała się powoli, a czas potrzebny na obsługę interakcji z użytkownikiem wydłuży się.
- Od samego początku wymagany jest JavaScript do wyświetlenia nawet podstawowych treści.
Zastosowanie
Tego typu aplikacje są obecnie szeroko spotykane. Na przykładzie React.js da się bardzo szybko utworzyć nowy projekt. Dawniej służyło do tego Create React App, obecnie coraz częściej wybierany jest Vite oferujący wiele szablonów: https://vitejs.dev/guide/#trying-vite-online
Zanim rozważysz taki wariant, weź pod uwagę wyżej wymienione wady i zalety. Poniżej damy Ci kilka porad jak ułatwić sobie proces decyzyjny.
Kiedy warto wybrać Client Side Rendering
- W przypadku aplikacji do "użytku wewnętrznego". Mamy tu na myśli wszelkiego rodzaju backoffice, dashboardy z dynamicznymi danymi itp.
- Jeśli tworzymy jakieś narzędzie, którego główną cechą ma być szybka reakcja na ruchy użytkownika
Kiedy lepiej poszukać czegoś innego:
- W momencie, gdy zależy Ci na świetnym pozycjonowaniu strony w wyszukiwarkach
- Dla witryn bazujących na dużej ilości statycznej treści. Przykładowo blogi, landing page itp.
Sposoby na optymalizację
Pomimo czyhających pułapek mamy też kilka sposobów na to, żeby zniwelować negatywne skutki nadmiernego obciążania urządzeń klientów. Oto najpopularniejsze z nich
Preloading
Skoro i tak musimy pobrać dodatkowe pliki, to zacznijmy to robić wcześniej. Chcąc szybciej wyświetlić cokolwiek użytkownikowi, warto odseparować krytyczny JS i pobrać go najszybciej jak to możliwe.
<link rel="preload" as="script" href="myCriticalJS.js" />
W ten sposób poinformujemy przeglądarkę, żeby zaczęła ładować skrypt myCriticalJS.js, zanim mechanizmy renderowania wystartują. Dzięki temu będzie on dostępny nieco wcześniej bez blokowania parsowania HTML’a.
Code splitting
Żeby nieco zmniejszyć rozmiar finalnego bundla, jesteśmy w stanie podzielić go na mniejsze części (chunki). Taką funkcjonalność oferują popularne bundlery jak Webpack czy Vite https://vitejs.dev/guide/features.html#build-optimizations https://webpack.js.org/guides/code-splitting/
Lazy Loading
Całość zaczyna zwalniać, gdy nasza aplikacja się rozrasta. A co, gdyby nie ładować całości od samego początku? Pozostając w świecie Reacta, pomocne może okazać się leniwe ładowanie niektórych komponentów:
import React, { Suspense } from 'react'; const SomeComponent = React.lazy(() => import ('./SomeComponent')): function MyComponent() { return ( <Suspense fallback={<div>Loading...</div>}> <SomeComponent /> </Suspense> ); }
Tree shaking
Nic tak nie denerwuje, jak płacenie za coś, czego nie używamy. Podobnie jest z kodem. Jeśli jakieś exporty nie są nigdzie używane, warto je wyrzucić z końcowego bundla. Vite robi to automatycznie, a w Webpacku da się to łatwo skonfigurować:
https://webpack.js.org/guides/tree-shaking/
Podsumowanie
Streszczając całość, można powiedzieć, że CSR poprawia User Experience, zapobiegając odświeżaniu strony. Robi to jednak nie za darmo, gdyż obciąża urządzenie klienta oraz wydłuża czas pierwszego ładowania aplikacji.
W jakich sytuacjach warto wybrać ten rodzaj renderowania? Biorąc pod uwagę zarówno wady, jak i zalety szczególnie wtedy, gdy kwestie związane z pozycjonowaniem w wyszukiwarkach nie są priorytetowe. Istotne jest natomiast zapewnienie wysokiego poziomu interaktywności.