Server-side rendering voor React web apps
In de begindagen van het internet was server-side rendering van HTML-pagina’s de enige optie. De wereld was eenvoudig: bij iedere klik op een link werd een compleet nieuwe pagina opgehaald van de server en getoond in de browser. Naarmate de kracht van javascript toenam, ontstond de mogelijkheid om pagina's ook (al dan niet gedeeltelijk) in de browser te renderen.
Door de voordelen van client-side rendering (zie onder) en het feit dat webpagina's steeds meer volledige, interactieve applicaties zijn geworden, zijn er in de afgelopen jaren frameworks ontstaan die client-side rendering makkelijk en efficiënt maken, zoals React, Angular en Vue.
Het grote nadeel van client-side rendering is dat de content minder makkelijk gevonden wordt door zoekmachines. Daar staat tegenover dat zoekmachines zich hebben aangepast aan het feit dat er steeds meer CSR-sites zijn bijgekomen. Sommige zoekmachines voeren bijvoorbeeld de javascript uit op pagina's van sites die veel bezoekers hebben, en de Google crawler indexeert tegenwoordig tot op zekere hoogte React-componenten (zie de links onderaan de pagina's).
Voordat we ingaan op de manier waarop wij server-side rendering voor React web apps gebruiken, eerst nog eens de voor- en nadelen van server- en client-side rendering op een rijtje:
Server-side rendering (ssr)
- Voordeel: pagina's zijn indexeerbaar voor zoekmachines
- Voordeel: snelle laadtijd eerste pagina
- Nadeel: veel contact (en dataverkeer) met de server en daardoor trager, want bij ieder request wordt de hele pagina opgehaald
- Nadeel: minder controle over de transities tussen pagina’s, zoals animaties
Client-side rendering (csr)
- Voordeel: na de eerste pagina laden de daarop volgende pagina's snel
- Voordeel: minder server verkeer
- Voordeel: paginaovergangen kunnen geanimeerd worden
- Voordeel: pagina's kunnen gedeeltelijk gere-rendered worden (bijvoorbeeld: er wordt een inlogformulier aan de pagina toegevoegd)
- Nadeel: pagina’s zijn niet ‘out of the box’ indexeerbaar door zoekmachines
- Nadeel: renderen van de eerste pagina duurt langer omdat eerst alle javascript ingeladen moet worden
Best of both worlds
Bij Tweede golf bouwen we vaak React webapplicaties waarvoor met name indexeerbaarheid een must is en daarom ssr noodzakelijk. We passen dan de volgende, conceptueel eenvoudige, combinatie van beide render methodes toe: de eerste pagina van de site of applicatie wordt server-side gerenderd en alle volgende pagina's client-side.
Omdat iedere pagina van een site of applicatie de eerste pagina kan zijn worden alle pagina's dus door zoekmachines geïndexeerd.
Een bestaande React-app kan heel eenvoudig omgebouwd worden naar ssr door gebruik te maken van een speciale methode genaamd renderToString. Hiermee wordt het root component van een React-app (of component) omgezet naar een kant-en-klare HTML string die je vervolgens in een HTML-pagina kunt plakken en door een webserver geserveerd kan worden.
React renderen op de server
Omdat React een javascript module is heeft de bovengenoemde methode renderToString, een javascript runtime op de server nodig. Alhoewel er libraries zijn waarmee je met een extensie React kunt renderen met php is deze methode niet aan te raden omdat deze libraries vaak traag zijn, nog experimenteel zijn of niet meer worden onderhouden.
Wij gebruiken daarom Nodejs met een http-server zoals Express of Koa. Deze server draait via een proxy achter de webserver. Theoretisch zou je ook de Nodejs-server als public-facing webserver kunnen gebruiken, maar wij kiezen liever een volwassen webserver zoals nginx die uitgebreide configuratiemogelijkheden heeft voor https, compressie en caching.
Daarnaast is het zo dat nginx veel sneller is in het serveren van statische assets zoals plaatjes, stylesheets, fonts en javascripts. De Nodejs-server serveert dus alleen een HTML-pagina met daarin de React-app en de referenties naar de statische assets die zoals gezegd door nginx geserveerd worden.
Als React op de client gerenderd wordt, krijgt de app een HTML-element op een pagina toegewezen, waarbinnen React de DOM-tree kan manipuleren. Deze HTML-pagina kan een statische pagina zijn of een bijvoorbeeld door PHP gegenereerde dynamische pagina. Bij server-side rendering renderen we zowel de React app als de HTML-pagina; op deze manier kunnen we ook in de HTML dynamische data schrijven zoals metatags die uit de database komen.
State Rehydration op de client
Doordat de pagina op de server gerenderd is, is het feitelijk een statische pagina geworden. Om de navolgende pagina's weer op de client te kunnen renderen moeten we de state rehydration uitvoeren. De javascript code die dit doet zetten we helemaal onderaan in de pagina net voor de closing body tag; hierdoor zie je eerst de hele pagina, vervolgens wordt de javascript ingeladen en ten slotte voeren we de state rehydration uit.
Rehydration is het proces waarbij je de client-side state afleidt (extraheert) uit de server-side gerenderde markup. Als je dit goed implementeert, triggert het hydrateren van de state geen nieuwe client-side render cycle. Tijdens het rehydrateren voegt React onder andere eventlisteners toe. Als Redux of een andere state management library wordt gebruikt is het nodig om de initiële state door te geven aan de javascript runtime, bijvoorbeeld via een globale variabele.
Meer lezen
Client-side rendering vs. server-side rendering.
Nieuwe features server-side rendering in React 16.
Wel of geen server-side rendering gebruiken?
Simpel voorbeeld van ssr met React (N.B. dit voorbeeld is met React 15).