You may have heard about server side rendering and may be bit confused by all these terms being thrown around. And is this related to React server components? (No, kind of, but not really).
Here’s a brief and maybe bit oversimplified explainer on what all these concepts mean.
Server Side Rendering
Client side rendering sucks 👎 Why?
- Poor initial page load - big bundle and rendering takes time
- Poor SEO - web crawlers only get blank HTML
Solution? Make server do most or all of the work. 👍
- Fast initial page load
- Great SEO - web crawlers get HTML with content
I will refer to server side rendering as ****pre-rendering**** also. The terms are synonymous; the pre-rendering generates HTML before the client, and the computer this happens in is the server. Pre-rendering is also a less ambiguous term since SSR can have a different meaning (explained below).
Question: when should the server do the rendering work? Initially when the server starts or when the client makes a request?
Build Time or Static Site Generation (SSG)
(Also called static rendering)
This is when the server starts up and pre-renders all the pages by creating all the HTML files and Javascript bundles - the content - beforehand.
This is great for content that will not change:
- Portfolios
- Marketing pages
- Documentations
- E-commerce product listings
Sites like Apple changes every few months or so, which is perfect for SSG
If a page requires dynamic data, such as updating the stock of a product, that can be done through client-side data fetching. The stock count will not be in the pre-rendered HTML but information like this can be excluded without impacting SEO or performance.
If the page can be pre-rendered ahead of the user’s request, then this approach works.
Request Time or Server Side Rendering (SSR)
What if the page ***can’t*** be pre-rendered ahead of client’s request? For example, take the home page of news sites such as New York Times, Los Angeles Times, etc. There will be new stories to display throughout the day. And if the user has an account and selected their preferences for topics, then the home page will have to be modified in regards to that as well.
Thus any pre-rendered content will likely be outdated by the time the client makes a request.
Hence, pre-rendering at request time. Also called dynamic rendering or server side rendering (Yes, it’s a bit confusing how developers reuse the same term to mean different things. Looking at you, NextJS docs 😠). Note: I don’t know what those sites do, this is just an example of where request time pre-rendering can apply.
Incremental Static Regeneration (ISR)
Well, pre-rendering every time the user makes a request can be costly. The news probably has not changed significantly within a minute. And if it did, they can wait and go touch grass.
Thus the concept of ISR: pre-render the page again at intervals.
- Let’s say interval is X seconds
- Client makes a request
- Server pre-renders the content, caches it, and sends the content to the client
- Client makes a request within X seconds
- Server sends cached content
- Client makes a request after X seconds
- Server invalidates cached content, pre-renders, caches, and sends content
Check back in a few hours later and the home page will be different
On-Demand Revalidation
What if you have very static sites that still needs to be updated from time to time but not:
- Every time the client makes a request?
- At time intervals?
For example, you need to change the metadata of a product on your e-commerce site - the price, description, category. If your database or headless CMS updates, this will make your server pre-render the relevant pages again and cache the new content.
This product page won’t change often and is perfect for on-demand revalidation.
Hydration Mismatch
This occurs when the pre-rendered HTML has a mismatch with the rendered content DOM in the server. This can occur for variety of reasons such as outdated cached Javascript or time differences. Here’s a very simple example to understand how this happens:
export default function Component = () => {
return <div>{Math.random()}</div>;
};
This is a simple server component in NextJS that is pre-rendered (server components are separate but related to pre-rendering). It outputs a random number.
Now I convert the server component into a client component by marking it with ‘use client’.
'use client'
export default function Component = () => {
return <div>{Math.random()}</div>;
};
This means that this component will still be pre-rendered by NextJS but this code will also be sent to the client.
Uh oh, there’s a mismatch. Math.random() executed again in the client and obviously output a completely different number. NextJS’s dev build displays errors for us as well.
Why does this matter? The client creates an internal representation of the page and maps the internal representation to the DOM elements of the pre-rendered HTML. This allows it to attach event handlers to the correct DOM elements. If there is a mismatch, interactivity can be broken or UI components can be duplicated. The example was a text mismatch but there can be element mismatch as well.
Conclusion
Client side rendering is still required for adding interactivity and displaying dynamic data. But it should no longer be used to render entire pages. Hopefully I explained these concepts well and if I didn’t and you have questions, please ask!
Top comments (0)