iJS CONFERENCE Blog

Server-side Rendering – Back to the Roots?

Hitchhiking through the JavaScript jungle

Aug 5, 2022

When it comes to modern web development, there's no avoiding big single page application frameworks like Angular, React, Vue, or even Svelte. The big advantage of this kind of web application is that, ideally, they feel like desktop applications to users. So there are no loading times between individual views. But the biggest disadvantage of these applications is their initial loading time.

This is because the current view and its data needs to be loaded, as well as the complete application with all views. Additionally, there’s a framework used in every case. None of these are really lightweight. The kind of application’s lifecycle has another peculiarity. Normally, the framework renders its components in an empty state and then communicates with a server interface that provides data for the display. Once the data is available in the frontend, the corresponding components are re-rendered.

But what does the process look like from the users’ point of view? I enter the application’s address in the browser and hit confirm. First, I see a white page. Wait, then the application’s frame, but no data. Then, suddenly, everything is there. Good user experience works differently. Of course, I can trick it with the browser cache or a service worker. But that doesn’t help with the application’s initial load. However, the second and all loading processes afterwards will be significantly faster. Another trick you can use to speed up the initial loading process is Lazy Loading. You don’t load all of the potential components in your application at the beginning, only those you really need. This makes a smaller bundle size and therefore, faster loading times. All of this is merely cosmetic, attempting to fool users into thinking it’s performance. But not everything needs to be fake. Modern frameworks contain features that allow completely different concepts. We’re talking about server-side rendering and static site generation. Let’s take a short look at both concepts and ask ourselves in secret if we’d rather go back to good old PHP for rendering dynamic websites on the server side.

iJS Newsletter

Keep up with JavaScript’s latest news!

Server-side Rendering

Server-side rendering, commonly abbreviated as SSR, refers to a workflow where a single page view of an application is rendered on the server side and delivered to the browser. Of course, for this to work, you need a corresponding infrastructure. The frontend frameworks are either implemented in JavaScript or TypeScript and are, more or less, tightly integrated with the browser’s DOM. In SSR, the DOM component doesn’t exist in this form. The rest of the runtime environment is also very different from the browser. In most cases, Node.js is used as the basis. This is an obvious choice because Node.js uses the same JavaScript engine as Chrome and Edge. The aim of SSR is to use Node.js to create an HTML structure that corresponds to the structure of the finished rendered application in the frontend. So, the typical empty div element that’s usually delivered by the web server into the application is then built with client-side JavaScript. This isn’t just about the empty frame structure of the empty rendered components, but the finished application with all user data. Achieving something like this is no mean feat. You can do it with traditional server-side programming languages and frameworks and you don’t need an additional frontend framework to do so. 

The whole thing only gets interesting due to the fact that after delivery and the initial display of the structure in the browser, the frontend framework takes control of the HTML structure. This process is called hydration. That means that in principle, SSR is also nothing more than a fake. After delivery, the users can’t do anything with the application because no interaction is possible (apart from the standard HTML elements). Only once the framework takes control can the application correspond to the state of the regular single page application, i.e., after all the data has been loaded.

However, usually, the effect for the users is clearly noticeable. SSR applications are delivered much quicker and provide visual results that users can work with much faster. Another beneficiary of this technology are the search engines or people optimising applications for search engines. Since the application no longer consists of an empty div element, but actual content, it’s easier for search engines to index. That usually awards a lot of positive points.

The individual steps that need to be completed for displaying in the browser are the same for traditional browser applications and SSR. Only the place where they are carried out differs. With SSR, you run the framework on the server-side with Node.js and load the data you need to display it on the server-side too. Then the application is delivered to the browser. The advantage here is that the users will see the finished application much faster, even if they can’t directly interact with it. You can also potentially save overhead caused by downstream data loading requests.

SSR in Practice

But how do the individual frameworks implement SSR in concrete terms? Let’s take a look at different implementations. We’ll start with Angular:

  • Angular: The framework shifts responsibility for SSR to a sub-project called Angular Universal. With this, you can render your Angular app server-side in an Express.js app, for example.
  • Vue: In Vue, SSR is somewhat more closely anchored to the framework itself. Here, you can use createSSRApp from the vue package to build your application. The actual transformation into a structure which you can deliver to browsers is done with the renderToString function from the vue/server-renderer package.
  • React: React, like Vue, has a separate sub-package that gives you the basics for SSR. Using functions like renderToString or renderToStaticMarkup from the react-dom/server package, you can create structures that you can deliver to your users over Node.js.
  • Svelte: Svelte is also prepared for operation in an SSR application. An additional tool called SvelteKit is often used. It supports SSR and many other tools and optimisations.

Similar to Svelte with SvelteKit, in other frameworks it’s common to not set up SSR in your application yourself, but rely on existing tools instead. In the case of React, a typical example is the Next.js framework.

In another step, you can even cache the rendered application on the server side. The advantage of this is that there’s no need to render and load the data on delivery, and the requested structure is immediately delivered. However, there’s usually a theoretical construction, as in most cases where the included individual information is only available after logging in. In this case, you must make sure that at least loading the data is decoupled from the rest in order to protect sensitive data.

 

EVERYTHING AROUND ANGULAR

The iJS Angular track

 

The idea of writing the SSR output in a cache has occurred to others before us. They’ve coined the term Static Site Generation for it. 

Static Site Generation

In Static Site Generation, abbreviated as SSG, a server process generates static HTML code from templates and dynamic data. In contrast to SSR, where the server process must always be running, with SSG it’s only needed for creating the structures. You can deliver the result (i.e., the rendered HTML) with a static web server. Various frameworks all have their own tools for SSG.

For example, the most popular tools for React are Gatsby or Next.js. In Vue, you can rely on Nuxt or VuePress. A widely used solution for SSG with Angular is Scully.

What did we learn from this?

At the moment, there’s no getting around single page applications on the web. This kind of application architecture has its advantages but also a few serious drawbacks. An SPA is a real heavyweight compared to a traditional website, since you have to download the HTML, CSS, and JavaScript of the current view as well as the entire application. One of developers’ most important goals is keeping a web application’s initial loading process as short as possible. Methods like Lazy Loading can help reduce the bundle size. SSR goes a decisive step further by having the server take on the role of the browser and pre-render the application, so the framework only needs to take control of the finished structure. In this case, the server process always needs to be active and answer the users’ incoming requests. SSG solves this problem by statically pre-generating individual pages that you can deliver with a web server.

STAY TUNED!

 

BEHIND THE TRACKS OF iJS

JavaScript Practices & Tools

DevOps, Testing, Performance, Toolchain & SEO

Angular

Best-Practises with Angular

General Web Development

Broader web development topics

Node.js

All about Node.js

React

From Basic concepts to unidirectional data flows