Client-side rendering: ce este, diferența față de SSR și când are sens
CSR înseamnă că browserul primește un HTML minimal și un bundle JavaScript, iar DOM-ul e construit pe loc. Rapid de livrat, dificil de indexat de Google.
Cuprins
Client-side rendering (CSR) este strategia prin care browserul primește un document HTML minimal, descarcă un bundle JavaScript, și construiește întregul arbore DOM direct în browser. Serverul nu livrează conținut randat: livrează cod. Pentru aplicații autentificate și panouri de administrare, asta e alegerea pragmatică. Pentru pagini publice indexate de Google, vine cu compromisuri serioase.
CSR a apărut ca pattern dominant odată cu SPA-urile din jurul anilor 2013-2015, când Angular, React și Ember au mutat randarea complet în browser. La momentul respectiv, Googlebot nu executa JavaScript deloc, ceea ce a creat un decalaj dureros: aplicații tehnic sofisticate, invizibile în căutare. Astăzi Google renderează JavaScript, dar cu întârziere. Presiunea în sens opus a dus la SSR și SSG ca standarde pentru paginile publice.
Ce este CSR (client-side rendering) mai exact?
O strategie de livrare în care serverul trimite un document HTML aproape gol, de obicei cu o singură etichetă rădăcină și un tag <script>, iar tot conținutul vizibil este construit ulterior de JavaScript în browser. Serverul nu știe ce pagină vei afișa în momentul cererii: browserul descide asta, pe loc.
Patru caracteristici care definesc CSR pur:
- HTML minimal la prima cerere. Răspunsul de la server conține metadate de bază, link-uri spre CSS și JS, și elementul rădăcină al aplicației. Conținutul real nu există în acel HTML.
- Bundle JavaScript descărcat și executat în browser. Framework-ul (Angular, React, Vue) rulează în browser, face cereri la API, primește date și construiește DOM-ul pe loc.
- Navigare fără full reload. Odată bundle-ul încărcat, tranzițiile între rute sunt gestionate de router-ul din JavaScript, nu de server. Asta produce o experiență fluentă, fără clipit de pagină.
- Stare persistentă în sesiune. Datele din memorie (cache local, stare UI) supraviețuiesc navigărilor între rute. Util în panouri complexe cu mulți pași.
Cum funcționează tehnic CSR?
La prima cerere HTTP, serverul răspunde în câteva milisecunde cu un document HTML de câteva kilobytes: un <head> cu metadate și referințe la assets, și un <body> cu elementul rădăcină gol. Browserul interpretează HTML-ul, descoperă tag-ul <script> și pornește descărcarea bundle-ului JavaScript.
Bundle-ul poate fi de zeci sau sute de kilobytes. Browserul îl descarcă, îl procesează și îl execută. Abia după execuție, framework-ul CSR preia controlul: citește URL-ul curent, decide ce componentă să randeze, face cereri la API pentru date, și construiește arborele DOM. Utilizatorul vede conținut real numai după ce toți acești pași se termină.
Fluxul complet pentru o singură pagină:
- Browser → server:
GET /blog/un-articol - Server → browser: HTML minimal (2-5 KB),
200 OKîn câteva ms - Browser descarcă bundle JS (50 KB, 200 KB sau mai mult, depending on app)
- Browser execută JS, detectează ruta
/blog/un-articol - JS → API:
GET /api/articles/un-articol - API → JS: datele articolului (JSON)
- JS construiește DOM-ul, inserează conținutul: utilizatorul vede pagina
Timpul de la cerere la conținut vizibil depinde de conexiunea utilizatorului, dimensiunea bundle-ului și viteza API-ului. Pe un laptop modern cu conexiune bună, câteva sute de milisecunde. Pe un telefon mid-range cu conexiune mobilă slabă, câteva secunde.
Care e diferența practică față de SSR?
SSR livrează HTML complet la prima cerere. CSR livrează HTML gol și lasă tot munca pe seama browserului. Diferența practică apare în patru arii:
- TTFB (Time to First Byte). CSR câștigă la TTFB: serverul răspunde rapid cu HTML-ul minimal, fără să aștepte baza de date sau API-ul. SSR are un TTFB mai mare pentru că serverul randează pagina complet înainte să trimită primul byte.
- FCP (First Contentful Paint). SSR câștigă clar. În CSR, FCP depinde de descărcarea și execuția bundle-ului JS plus cel puțin un apel API. În SSR, FCP apare imediat după primirea HTML-ului, care conține deja conținut randat.
- SEO și indexare. SSR câștigă. Googlebot poate indexa HTML-ul livrat direct. Cu CSR, Googlebot trebuie să execute JavaScript, să aștepte API-urile și să rendeze DOM-ul. Indexarea e amânată cu ore sau zile și poate fi incompletă. JSON-LD în HTML-ul randat de server ajunge garantat la Googlebot; JSON-LD injectat de JS ulterior, mai puțin sigur.
- Comportament fără JavaScript. SSR afișează conținut și fără JavaScript activ. CSR afișează o pagină goală. Relevanța practică a scăzut (utilizatorii cu JS dezactivat sunt rari), dar rămâne un factor pentru crawlere speciale și meta robots testați manual.
O regulă practică: dacă pagina trebuie să apară în rezultatele căutării Google fără să aștepți ore întregi, SSR sau SSG sunt răspunsurile corecte. CSR rămâne potrivit pentru zone autentificate, panouri de administrare, și orice pagină marcată explicit cu noindex.
De ce am ales SSR pentru paginile publice și unde mai folosim CSR?
Pentru paginile publice ale crawlerra.com folosim Angular SSR. Body-ul HTML randat de server are aproximativ 47 KB pentru un articol publicat1, suficient pentru crawl Google și prima vopsire rapidă. Procesul SSR Node rulează cu o limită de heap de 192 MB2, setată după ce un abonament reactiv neînchis a dus RSS-ul la peste 800 MB în 48 de ore: limita forțează un restart controlat prin systemd, în loc să lase procesul să consume toată memoria gazdei.
CSR rămâne alegerea pragmatică pentru zona /admin/ unde nu vrem indexare și unde timpul până la interactivitate contează mai puțin decât interactivitatea propriu-zisă. Paginile de administrare au noindex prin meta robots și nu apar în sitemap.xml. Nu există niciun beneficiu SEO de apărat acolo, iar complexitatea unui SSR pentru o interfață de admin nu se justifică. Același principiu se aplică oricărui portal de client sau dashboard intern: dacă pagina e în spatele autentificării și Google nu trebuie să o vadă, CSR simplifică arhitectura fără niciun cost real.
Care sunt capcanele tipice ale CSR?
- FOUC (Flash of Unstyled Content) și conținut care apare târziu. Utilizatorul vede câteva momente un schelet gol sau conținut nestilit înainte ca JS-ul să construiască DOM-ul. Pe conexiuni lente sau device-uri cu CPU slab, fereastra asta se extinde la secunde întregi. Spinere generice nu rezolvă problema, ci o maschează.
- SEO pe SPA fără prerendering. O aplicație CSR fără SSR sau SSG produce pagini invizibile pentru Google în primele ore după publicare. Dacă adaugi hreflang sau canonical via JavaScript, Googlebot le vede cu întârziere sau deloc la prima trecere. Injectează-le în HTML la server.
- Bundle mare pe device-uri slabe. Procesarea și execuția unui bundle de 500 KB de JavaScript ia peste un secund pe telefoane mid-range. Utilizatorii pe device-uri slabe au CPU de două-trei ori mai lent decât un MacBook. Code splitting și lazy loading amână problema dar n-o rezolvă complet; la un moment dat, cantitatea de JS devine factorul limitant.
- Dependență de API la prima încărcare. Dacă API-ul e lent sau cade, utilizatorul vede un spinner sau o eroare. SSR permite cache la nivelul HTML-ului generat; CSR nu are această opțiune nativă. Fiecare utilizator nou e un consumator direct al API-ului, fără buffer.
- Stare care nu se sincronizează cu URL-ul. SPA-urile CSR trebuie să gestioneze explicit istoricul browserului și parametrii de URL. O implementare neglijentă produce URL-uri care nu pot fi bookmark-uite sau partajate, sau care pierd starea la refresh. Testează întotdeauna comportamentul la reload direct și la accesare directă a unui URL profund.
- Mărimea HTML-ului randat de server pentru un articol din blog, măsurată cu
curl -sS https://crawlerra.com/blog/cum-scriem-articolele | wc -c.[crawlerra.ssr_body_size] - Limita de heap
--max-old-space-size=192a fost setată după ce procesul SSR a depășit 800 MB RSS în 48 de ore din cauza unui abonament reactiv care nu se închidea.[ops.angular_memory]
Întrebări frecvente
CSR este întotdeauna rău pentru SEO?
Nu, dar SEO pe pagini CSR pur cere mai multă atenție și acceptă mai mult risc. Google renderează JavaScript, dar cu o întârziere de ore sau zile față de prima descoperire a paginii. Dacă conținutul tău se schimbă rar și ai timp să aștepți re-renderarea Google, CSR e funcțional. Dacă indexarea promptă contează (blog, catalog, landings), SSR câștigă de fiecare dată.
Ce este hydration și de ce contează?
Hydration este pasul în care JavaScript atașează logica interactivă unui HTML deja randat. În SSR, serverul livrează HTML complet; browserul îl afișează imediat, apoi rulează bundle-ul JS care „învioreazâ" componentele. În CSR pur nu există HTML de randat pe server, deci nu există hydration propriu-zis: JS construiește totul de la zero în browser.
FOUC înseamnă că am CSR?
Nu neapărat, dar e un semn că randarea e amânată față de livrarea CSS-ului. FOUC (Flash of Unstyled Content) apare când CSS-ul sau fonturile ajung după ce DOM-ul e deja pictat. Poate apărea și în SSR dacă faci lazy-load la CSS. Dar în CSR e mai frecvent pentru că DOM-ul întreg apare odată cu execuția JS, nu progresiv.
SPA înseamnă automat CSR?
Nu. Un SPA (single-page application) poate folosi SSR sau SSG pentru prima încărcare și CSR pentru navigările ulterioare. Angular Universal, Next.js și Nuxt fac exact asta: SSR la prima cerere (pentru SEO și FCP rapid), then CSR pentru tranzițiile în pagină (fără full reload). Termenul SPA descrie modul de navigare, nu strategia de randare inițială.
Pot folosi CSR și totuși să fiu indexat corect de Google?
Da, dacă adaugi prerendering sau SSG pentru paginile publice și tratezi corect meta tag-urile. Soluții precum prerendering static (Angular SSG, Next.js static export) generează HTML la build time fără să ceri SSR la runtime. Atenție: paginile cu date dinamice nu pot fi prerandate corect. Și chiar și cu prerendering, JSON-LD și canonical trebuie să fie prezente în HTML-ul livrat, nu injectate de JS ulterior.