Some years ago, when I started doing web development all the dynamic pages were rendered on the server-side, you know multi-page applications or MPAs i.e the client requested some content and the server responded with a ready to render the page. This approach is pretty simple and known as server-side rendering.
That was great until the more interactive content started being displayed on web pages. As the whole page was re-compiled by the server-side and the browser rendered the complete HTML page every time the client requested, so even updating a small portion of the page was a pain.
Table of Contents
Client-Side Rendering (CSR)
Nowadays the more advanced web technology has made life easier with Angular, React, and other JavaScript frameworks which work inside the browser and don’t require page reloading during use. This approach is known as client-side rendering (CSR).
With client-side rendering, web applications made it possible to create a dynamic experience that we came to know as single-page applications (SPAs). It’s structured as a single HTML page with NO preloaded content.
All the HTML generation is done on the client-side. Whenever a link is clicked instead of sending a request to the server for HTML of that page, HTML is created on the client-side by mounting a new component.
Content is loaded via API calls housed within a single HTML page. URLs in the browser are changed via history API which doesn’t result in browser refresh.
As there is no page refresh ever, we only ask for the app’s code once which includes HTML, JavaScript, CSS, and other assets of the entire app in a bundle form. With the introduction of virtual DOM, the experience became more smooth as well. Here is an example of the initial page in CSR:
<!DOCTYPE html> <html lang="en"> <head> <title>CSR Example</title> </head> <body> <div id="root"></div> </body> </html>
In the above HTML, <div id=“root”></div> is the container or the root element of the SPA. All application HTML generated by our JavaScript will be populated inside this element on the client-side.
Can CSR be a Nightmare For Your Website?
In client-side rendering, all code like HTML, CSS, and JavaScript with all the static assets are sent in one bundle.
This bundle once loaded, allows the web browsers to render a meaningful web page for the user. Page navigation will be fast and there will not be any additional loading time between different parts of the application. It works pretty well and provides a seamless user experience, but these client-side rendered applications always need to make an additional round-trip to the server to render.
This means your application loading will always be slower than the equivalent server-rendered application and it will become an issue if:
- the application grows in size and complexity
- the end-user is using a slow internet connection
- the end-user is running an underpowered device
In the above-mentioned situations, loading the initial bundle can take a significant amount of time and make your site slow. It’s not surprising that with the significantly increased load time and not having meaningful content on the first render, CSR can lead your application to some serious problems like
- Nearly impossible to maintain good SEO because of a lack of initial content on the HTML.
- Deterioration of user experience due to massive increase in initial load time.
The solution is something we used to do a lot but forgot in favor of client-side rendering and that is server-side rendering but with a modification of using it with client-side rendering.
Server-Side Rendering (A Hybrid Approach)
At the end of the day, we want a hybrid of new (client-side rendering) and old (Rendering on the server-side) approaches. We want a fully rendered HTML from the server for SEO and performance, and at the same time, we want the speed and flexibility of client-side applications (SPAs).
Now modern web development is kind of coming back to the approach of rendering on the server, at least for the first page and it’s not exactly like rendering on the server discussed above, that’s why it has a new name Server-side rendering.
There are a couple of differences between rendering on the server and server-side rendering, the one most important difference is the concept called isomorphic javascript.
Looking for a Web Development Team?
Share the details of your request and we will provide you with a full-cycle team under one roof.
What is Server-Side Rendering (SSR)?
Server-side rendering is the ability of an application to render meaningful HTML on the server and send it to browsers or other user agents. After the initial view is rendered, the client’s javascript bundle is downloaded in the background and subsequent actions are handled client-side.
When a user requests the first time, SSR sends fully rendered HTML with user-specific data to the client and then the client’s JavaScript bundle takes over and enables the client-side rendering process to operate, this new kind of application is known as an isomorphic app.
Here is an example of the initial page in SSR:
<!DOCTYPE html> <html lang="en"> <head> <title>SSR Example</title> </head> <body> <div id="root"> <h3>World's happiest countries</h3> <ol> <li>United Kingdom</li> <li>Pakistan</li> <li>South Africa</li> <li>Australia</li> </ol> </div> </body> </html>
How it works:
In server-side rendering, the same javascript code needs to be compiled on both servers and on the client. For this purpose node server is needed at the server-side so javascript code can be run inside it on the server.
When a user requests a web page, the server generates an HTML page from javascript code inside the node server and prepares meaningful HTML by fetching user-specific data and then sending it to the client.
The browser then displays the ready-to-render webpage. This entire process of fetching data from the database, creating a renderable HTML, and sending it to the client happens in a few milliseconds.
In this way SSR lets your users see the webpage before the JavaScript bundle loads and runs at the user end.
Meanwhile, your application’s code (javascript bundle) is downloaded in the background. However, the webpage can’t be interactive before the javascript code fully loads.
When your javascript bundle is loaded, Now it’s time to attach event handles to already rendered HTML. With technologies like virtual DOM, clients can effectively hook up event handlers to already pre-existing HTML instead of rebuilding it from scratch via a process called “Hydration”.
The process of rendering your client-side code and attaching event handlers to already existing HTML is known as Hydration. After hydration, it works like a usual client-side rendered app.
If I summarize the working of SSR, the process usually happens in a few steps:
- On the server, fetch data for the first page, prepare the HTML, and send it to the client.
- Then, the client renders the web page without having any dynamic features like event handlers.
- The server then sends client-side application code i.e javascript bundle, which is run by the client.
- Then the rendered webpage is finally hydrated with the javascript bundle making it interactive.
In simple terms, SSR works by preparing the HTML with user-specific data in advance to reduce the load time as the user will see the fully rendered webpage at once.
This whole process makes the initial load time of the page much faster. However, page won’t be interactive until the actual javascript bundle downloads from the server and takes over.
So, you get the display from the server and interactivity or functionality from the same code running on the client-side, and from that point, as you navigate through the additional pages on the client side then those pages are client-side rendered as you do in the CSR.
Here is the flow chart of working of SSR with SPAs:
Benefits of using SSR:
The downside of using CSR can be handled gracefully here and there would be noticeable improvements in your application by using the SSR approach, even if the end-user is running a slow internet connection or underpowered device. Also, the application can be loaded if javascript is disabled on the browser. Here I’ll discuss in detail one most important and major benefits of using server-side rendering with SPAs.
Search and Sharing:
The single biggest benefit of SSR is to maximize your reach. It plays an important role in SEO (search engine optimization). In this modern world, every app needs to have users and the best way to get traffic on your website is through search engines and social sharing. Both rely on non-browser agents called “bots”.
Search bots crawl the web page and populate search indexes while link bots visit links and produce visual snippets to encourage sharing.
Many of these bots don’t run client-side code, so if meaningful content is not served then your webpage will be invisible to the search engines.
By using SSR, initial page rendering is done on the server and complete HTML of the first page with all of the meaningful content is served. So, most of the bots can easily run this code and this aspect of your app is optimized for SEO. It’s a huge benefit over just using CSR/SPAs.
Is SSR Needed For The Performance?
SSR helps to get something as quickly as possible on screen but does not guarantee that performance will be good.
We have discussed in SSR that the initial page will not be interactive right after loading. Event handlers need to be hooked to make it interactive and it’s done after javascript runs on the client-side. It depends on the size of the application i.e JS bundle and SSR don’t do anything to make the page interactive faster.
So whether to paint quickly or get interactive quickly depends on the nature of the app. If the app has more static content then it’s not a major issue but if the app is user-driven then it should be a huge concern.
Besides fast interactivity, it’s the fact that SSR is viewed as a magic bullet in loading performance.
So, we don’t need SSR to achieve excellent performance. If that’s the only purpose then using patterns like PRPL, great performance can be achieved without SSR.
Challenges and Pitfalls:
SSR is super elegant and is a great choice for building apps but nothing is perfect, SSR also has some complexities and challenges. Of course, workarounds are there as well.
- SSR for smaller applications can improve performance. But, for complex and large applications it may degrade the performance due to increased time between first print and user interactivity.
- JavaScript needs to be compiled both on the server and on the client. It can be costly and resource-intensive. Also, SSR increases the complexity of the application. Javascript context which is available in the browser is not available on the server. So objects like window dots are not accessible on the server.
- Any state generated on the server will not be passed to the client. The HTML generated on the server has user-specific data. And it will not be placed in this.state that the browser can see. That’s why, when it’s hydrated on the browser, the component renders with an empty state. And so there is a mismatch between the server HTML and browser HTML.
- Rendering on the server may not be compatible with third-party javascript code. If things like Router, i18n, react-loadable, etc are used, these all need to be configured on the server.
Conclusion
After all, SSR has definite benefits over CSR and it addresses the concerns in CSR by creating HTML on the server. Search engines can index your URLs. Visitors can share them on Facebook or Twitter. But, using SSR depends on some factors like the app’s complexity, user experience priorities, and the scale of the project.
Recommendations
There are some libraries/frameworks to help implement SSR with modern technologies like React and Vue etc. If you want to work with React then Next.js is a great framework with a great community around it. Another one is Razzle, a project by Jared Palmer. Also, for static-sites GatsBy has exceptional user and developer experience. Nuxt.js is a server-side rendering framework for Vue.js and is popular in the Vue.js community.