I am baffled by the lack of concrete information about how Client-Side Rendering (CSR), Server-Side Rendering (SSR), and Static Site Generation (SSG) actually work.
There are tons of articles loosely explaining the concepts, but I have not found a single source that goes in-depth and explains exactly what HTML, CSS and JS are created on the server vs on the client, in the three concepts.
From the Next.js docs, we can read that:
- With Static Rendering, both Server and Client Components can be prerendered on the server at build time.
- Client Components have their HTML and JSON prerendered and cached on the server. The cached result is then sent to the client for hydration.
- Server Components are rendered on the server by React, and their payload is used to generate HTML. The same rendered payload is also used to hydrate the components on the client, resulting in no JavaScript needed on the client.
Note: Static Rendering is equivalent to Static Site Generation (SSG) and Incremental Static Regeneration (ISR).
And:
- With Dynamic Rendering, both Server and Client Components are rendered on the server at request time.
Note: This is equivalent to Server-Side Rendering(getServerSideProps()).
Fine, so Static Rendering equals Static Site Generation (SSG), meaning that some html+css is created build-time. Exactly what html is created build-time depends on whether you use Client Components or Server Components.
I inspected the built public
folder of a built Gatsby project and noticed that none of the React components were actually turned into html (regardless of whether they depended on user interaction). Gatsby had created an html file for each page, but the <body>
of each of those was still React components defined in JS, expecting to be turned into html by React on the client, run-time. This breaks with my understanding of the second bullet from the Next.js docs, which states that the html is "prerendered".
Questions
By the above docs, could we say that Static Site Generation (SSG) actually requires both Server-Side Rendering (SSR) and Client-Side Rendering (CSR)?
If so, does that not conflict with the Dynamic Rendering definition above, which states that Dynamic Rendering is equivalent to Server-Side Rendering?
Finally, exactly what html+css+js is created upon Static Rendering with Client Components?
Bouncing back and forth between frameworks makes this a bit harder to answer concretely, so I'll focus mostly on Next.js here.
There are really only two places React components are converted into HTML representations[^1]: the server, and the client/browser. Excepting Next.js Server Components, all React components are always rendered in the browser. Thus, your questions are mostly about server-side rendering.
The difference between SSG and SSR is when the rendering happens and the information available to the components at that time, not the HTML output. Any SSG-compatible page would produce the same result via SSR, albeit less efficiently.
Next.js is using the terms “Static” and “Dynamic” to refer to SSG and SSR, respectively. They also include ISR (incremental static generation) in SSG because it works similarly, just delayed.
With that understanding, let's look at your questions:
By the above docs, could we say that Static Site Generation (SSG) actually requires both Server-Side Rendering (SSR) and Client-Side Rendering (CSR)?
No. SSR implies that the rendering is happening in response to a request. SSG happens in advance (and in an isolated context from requests, typically). Thus they are mutually exclusive, though both can happen in the same application.
If so, does that not conflict with the Dynamic Rendering definition above, which states that Dynamic Rendering is equivalent to Server-Side Rendering?
Next.js is using the term “Dynamic” to refer to SSR—where pages are generated in response to and with access to the request—for clarity.
Finally, exactly what html+css+js is created upon Static Rendering with Client Components?
For vanilla React, all components render on the client. Next.js has a newer, somewhat experimental implementation for components that are only rendered on the server, resulting in no JS payload for them to be run on the client. This is effectively SSR/SSG but where some components are never hydrated.
In vanilla React, when rendering a component on the server, the HTML/CSS for the page is sent to the client, along with the JS needed to hydrate (load React client-side and attach to that HTML).
If you are using Next.js Server Components, the same HTML/CSS is generated, but less of your component JS will be bundled and sent to the client.
Regarding your Gatsby example, when using SSG, Gatsby builds static HTML pages for each of the pages it knows about, and includes the JS needed to hydrate the page into a single-page app with Gatsby’s client-side routing configured. I strongly suspect you have either checked the public
folder during development with SSR disabled, or in an earlier version of Gatsby that didn't support SSR in development. If I'm mistaken, you might need to review how you have Gatsby configured because that is not typical.
^1: I'm speaking loosely here. Components are rendered and React determines from their output what manipulations (if any) to make to the DOM. Not all components even produce elements to render. Yadda, yadda.