Introductions
There are many ways a website can be rendered depending on the underlying use case. A website is ultimately a combination of HTML (view), CSS (styles) and JS (interactivity).
First, we need to know what is Hydration
Hydration is attaching event listeners to the HTML elements in the page, that is done by the browser which is prescribed in the JS code.
Static Rendering
In this type,
- HTML gets generated at build-time.
- Document is easily cacheable by the nearest CDN.
Even this type of rendering has got several variations.
Plain Static Rendering
In this type,
- Whenever the document is requested from the server, the CDN makes a copy of it after first serve, and then serves the cached response next time.
- If at all any interactivity is involved, some JS is attached with the document.
- After rendering the HTML, the client then makes a request to fetch the JS.
- This JS then hydrates the components on the page.
This is suitable for websites which are,
- not at all dynamic in nature.
- does not contain any personalized data/
- can be cached globally.
In terms of performance measures,
- It has a quick Time to first byte (TTFB).
- Since, the entire HTML gets generated and passed to the browser, First Contentful Paint (FCP) and Largest Contentful Paint (LCP) is the same.
- We don’t need to worry about Cumulative Layout Shift (CLS), as the entire layout gets delivered in one go.
Static Rendering with Client-side fetch
In this type,
- It’s all same as Plain Static Rendering, but in this case, data on the page is queried by making a fetch call.
- The data is fetched on every refresh. Initial HTML layout contains some kind of skeleton UI as a placeholder for upcoming data, which gets cached at CDN level.
- Once HTML is received, a request is made for the JS script, which when executed by the browser, makes the fetch call.
This is suitable for websites which,
- Have got dynamic data.
- contains data that should refresh on every page load.
In terms of performance measures,
- TTFB will again be quick.
- FCP will remain the same, its the LCP which suffers.
- CLS can be affected due to the jumps in page caused by incoming data if not handled correctly.
Static rendering with getStaticProps
In this type,
- The server is the one who makes the API call at build time to populate the data in the HTML which is then sent to the client.
- This HTML which contains the pre-rendered data, gets cached by the CDN.
- In NextJS, this is possible via getStaticProps, wherein each route is pre-built beforehand on the server.
This is suitable for websites which,
- have got data ready at build time.
- can be cached globally.
- data is not user specific.
- data is not that dynamic in nature, because to pre build the pages again, we’ll have tp redeploy the website.
In terms of performance measures,
- It’s the same as that of Plain Static Rendering, but with the chance of higher initial build times.
- Which means TTFB can be delayed at initial renders.
Incremental Static Regeneration
In this type,
- To solve the dynamic data issue with the above technique, the pages will get rebuilt or revalidated after certain interval or on-demand.
- Some pages will get pre-built and some on-demand.
- In Next JS, we specify what paths or routes we want to pre build using getStaticPaths, and we specify the interval by the revalidate flag.
- If we want to pre-render only certain routes, we need to include a flag fallback as true as well in getStaticPaths.
- Pages will get served from CDN cached, and once available in the browser, the revalidation counter will check when the server needs to build the page again.
- At that time, it rebuilds the page and removes the older page with stale data from the CDN cache.
- This can result in lower build times.
This is suitable for websites which,
- Have got dynamic data.
- data is not user specific.
- data needs to be refreshed after certain interval or on demand.
- can be cached globally.
In terms of performance measures,
- It can lead to higher server costs, as pages will get pre-rendered after a regular interval, even when data is not changed.
On-demand Incremental Static Regeneration
This type is nothing but Incremental Static Regeneration without the automatic revalidation interval.
Pages will get pre-rendered on-demand, and will rely on revalidate requests, as an example, when API tells whether data was updated or not.
We are eliminating the unnecessary pre-rendering pages even when the data has not updated, and hence, is cheaper.
Server Side Rendering
In this type,
- Page is pre-rendered/built on every request to the route.
- Not much use of CDN caching here as the data in the page might be unique for each request.
This is suitable for websites which are,
- highly dynamic and personalized in nature.
- need new data on every request, as it keeps on changing.
- highly user-specific, which uses request-based data such as cookies.
- which use authentication and authorization.
SSR can be further optimized by using Cache-Control on API calls made to obtain the data.
In terms of performance measures,
- TTFB has suffered because a new page is generated on every request.
- LCP is same as FCP.
- No CLS as page is rendered on server side.
- But since, TTFB was delayed, TTI and FID will also get delayed.
Streaming SSR + React Server Components
One thing we can do is combine the advantages of static as well as server side rendering for the same page.
It might happen that there can be certain parts of the page which require user-specific highly dynamic data for which SSR can be used, and for the rest of the page, Static rendering can be used.
React Server components can be used for such components, which will rebuilt on demand on the server.
Client Side Rendering
In this type,
- Server has got little work, to just send the JS to the client.
- Client fetches the data and populates the HTML.
- Client also handles routing and revalidation of data.
This is suitable for websites which are -
- highly interactive in nature.
- initial load times (FCP/LCP) are not important.
- don’t want server to do much.
Comparison
Comparison between all these techniques roughly looks like this -