Home > Article > Web Front-end > The Junior Developers Complete Guide to SSR, SSG and SPA
Every dev tools company and -team seems to assume that Junior Devs are familiar with these terms.
When I started to code, I saw them everywhere: Nuxt is an SSR framework, you can use Gatsby for SSG, and you can enable SPA mode if you set this or that flag in your next.config.js.
What the hell?
As a first step, here's a glossary – though it won't help you to understand the details:
Next, let's shed some light into the dark.
Initially, a website was an HTML file you requested from a server.
Your browser would ask the server, "Hey, can you hand me that /about page?" and the server would respond with an about.html file. Your browser knew how to parse said file and rendered a beautiful website such as this one.
We call such a server a static web server. A developer wrote HTML and CSS (and maybe a bit of JS) by hand, saved it as a file, placed it into a folder, and the server delivered it upon request. There was no user-specific content, only general, static (unchanging) content accessible to everybody.
app.get('/about', async (_, res) => { const file = fs.readFileSync('./about.html').toString(); res.set('Content-Type', 'text/html'); res.status(200).send(file); })
Static websites are, however, boring.
It's much more fun for a user if she can interact with the website. So developers made it possible: With a touch of JS, she could click on buttons, expand navigation bars, or filter her search results. The web became interactive.
This also meant that the /search-results.html page would contain different elements depending on what the user sent as search parameters.
So, the user would type into the search bar, hit Enter, and send a request with his search parameters to the server. Next, the server would grab the search results from a database, convert them into valid HTML, and create a complete /search-results.html file. The user received the resulting file as a response.
(To simplify creating request-specific HTML, developers invented HTML templating languages, such as Handlebars.)
app.get('/search-results', async (req, res) => { const searchParams = req.query.q; const results = await search(searchParams); let htmlList = '<ul>'; for (const result of results) { htmlList += `<li>${result.title}</li>`; } htmlList += '</ul>'; const template = fs.readFileSync('./search-results.html').toString(); const fullPage = embedIntoTemplate(htmlList, template); res.set('Content-Type', 'text/html'); res.status(200).send(fullPage); });
For the longest time, I found the term rendering highly confusing.
In its original meaning, rendering describes the computer creating a human-processable image. In video games, for example, rendering refers to the process of creating, say, 60 images per second, which the user could consume as an engaging 3D-experience. I wondered, already having heard about Server Side Rendering, how that could work — how could the server render images for the user to see?
But it turned out, and I realized this a bit too late, that "rendering" in the context of Server- or Client-Side Rendering means a different thing.
In the context of the browser, "rendering" keeps its original meaning. The browser does render an image for the user to see (the website). To do so, it needs a blueprint of what the final result should look like. This blueprint comes in the form of HTML and CSS files. The browser will interpret those files and derive from it a model representation, the Document Object Model (DOM), which it can then render and manipulate.
Let's map this to buildings and architecture so we can understand it a bit better: There's a blueprint of a house (HTML & CSS), the architect turns it into a small-scale physical model on his desk (the DOM) so that he can manipulate it, and when everybody agrees on the result, construction workers look at the model and "render" it into an actual building (the image the user sees).
When we talk about "rendering" in the context of the Server, however, we talk about creating, as opposed to parsing, HTML and CSS files. This is done first so the browser can receive the files to interpret.
Moving on to Client-Side Rendering, when we talk about "rendering", we mean manipulating the DOM (the model that the browser creates by interpreting the HTML & CSS files). The browser then converts the DOM into a human-visible image.
With the rise of platforms like Facebook, developers needed more and faster interactivity.
Processing a button-click in an interactive web app took time — the HTML file had to be created, it had to be sent over the network, and the user's browser had to render it.
All that hassle while the browser could already manipulate the website without requesting anything from the server. It just needed the proper instructions — in the form of JavaScript.
So that's where devs placed their chips.
Large JavaScript files were written and sent to the users. If the user clicked on a button, the browser would insert an HTML component; if the user clicked a "show more" button below a post, the text would be expanded — without fetching anything.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="root"></div> <script> document.addEventListener('DOMContentLoaded', () => { const root = document.getElementById('root'); root.innerHTML = ` <h1>Home</h1> <button>About</button> `; const btn = document.querySelector('button'); btn.addEventListener('click', () => { root.innerHTML = ` <h1>About</h1> `; }); }); </script> </body> </html>
Though the code snippet suggests the opposite, developers didn't write vanilla JavaScript.
Ginormous web apps like Facebook had so much interactivity and duplicate components (such as the infamous Like-button) that writing plain JS became cumbersome. Developers needed tools that made it simpler to deal with all the rendering, so around 2010, frameworks like Ember.js, Backbone.js, and Angular.js were born.
Of them, Angular.js was the one that brought Single Page Applications (SPAs) into the mainstream.
An SPA is the same as Client-Side Rendering, but it is taken a step further. The conventional page navigation, where a click on a link would fetch and render another HTML document, was taken over by JavaScript. A click on a link would now fire a JS function that replaced the page's contents with other, already preloaded content.
For this to work properly, devs needed to bypass existing browser mechanisms.
For example, if you click on a
Devs invented all kinds of hacks to bypass this and other mechanisms, but discussing those hacks is outside the scope of this post.
So what were the issues with that approach?
SEO and Performance.
First, if you look closely at the above HTML file, you'll barely see any content in the
tags (except for the script). The content was stored in JS and only rendered once the browser executed the