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.
Keep up with Angular’s latest news!
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.
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?