Nowadays, many frameworks support SSR, and it is becoming a standard for every website with FCB (First Contentful Paint), which occurs when we type a URL on the browser, and the corresponding website will appear in a blink. Moreover, websites with SSR have a better SEO. However, their TTI (Time to interact) is really poor, and this disadvantage is difficult to improve. This is due to the drawback of some traditional Hydration methods. Nevertheless, a new face comes to play, Resumability - a potential way to add interactions to SSR websites.
Overview of Client-side rendering and Server-side rendering
Client-side rendering (CSR)
In client-side rendering, when a user wants to access a website, the browser sends requests to the server and eventually receives HTML, CSS, and JS files from the server. The browser executes those files and renders a dynamic website where users can see and interact with the content.
Because of how CSR works, it may take time to make websites using Client-side rendering visible to the users in case of poor Internet connection or complicated websites with large sizes. In such cases, users usually see a blank page. Furthermore, CSR websites cannot support a good SEO because there is no information about the website provided in the web’s source code.
The following example provides a good sense of CSR. The source code contains no information about the web. We can also see HTML, CSS, and JS files sent from the server. These files are eventually rendered by the browser, as mentioned above.
Server-side rendering (SSR)
In server-side rendering, when a user wants to access a website, the browser sends requests for that page to the server and eventually receives a full-content HTML page. Instead of spending some time executing JS files like CSR, the browser just needs to display the page using provided HTML files. Users can soon see the content of the website instead of having a blank screen in front of them.
SSR websites support effective SEO since all the information is contained in the source code. The example below shows a contentful source code of GeeksforGeeks website.
Hydration in Server-side rendering
As discussed above, SSR seems to be a good way to go when coding our website with certain benefits like improving SEO and decreasing the initial load time (the user does not have to see some boring blank space). However, the page that the browser shows us initially is not yet interactable for 1 second or more (we cannot click some buttons or type some inputs).
Looking at the figure below, the green components are interactable components, and the gray color is a static one.
We can see that although the user can see some content on the SSR website, they can not do anything to the page because the page is just a plain static HTML file with no event handlers attached. This is when Hydration comes to play.
Hydration is a method in which interactions are added to the static HTML files sent from the server to the browser.
Let’s take a look at this example. Suppose we have a static HTML file sent from the server with 2 button components. There is nothing the user can do with them. Therefore, we have to “hydrate” them by attaching some event handlers to them. To do this, besides receiving HTML files from the server, the client also has to fetch all the JS files (just like CSR) and re-execute them to find what components to bind to corresponding DOM Elements.
So, what happened with the websites using Server-side rendering?
The SSR architecture requires the server to execute JS codes and render a static HTML to the client. However, the client cannot just use it right away, it has to fetch JS codes and do the exact same thing as the server does - executing them again to find the exact event handler to bind to the correct DOM elements. This hydration process wastes quite a lot of time and resources. It can take up to 10s for a mobile phone to load a fully interactive SSR website if that website is heavy.
Resumability - The new solution to replace expensive Hydration
Nowadays, most frameworks’ hydration is re-executing codes, a.k.a repeating jobs which were previously done on the server. Qwik - a new framework that has a different thought. It is execution should be done partially on the server, paused, and resumed at the client (Resumability). Thus, no extra work is done, and the web application will become faster.
Existing frameworks solve the event listener by downloading the components and executing their templates to collect event listeners that are then attached to the DOM. The current approach has these issues:
- Requires the template code to be downloaded in advance.
- Requires template code to be executed in advance.
- Requires the event handler code to be downloaded in advance to be attached.
The above approach does not scale. As the application becomes more complicated, the amount of code needed to download beforehand and execute grows proportionally with the size of the application. This negatively impacts the application startup performance and hence the user experience.
Qwik solves the problem by serializing the event listens into DOM as below:
<div q:host> <div q:host> <button on:click="./chunk-a.js#greet">Greet</button> </div> <div q:host> <button q:obj="1" on:click="./chunk-b.js#count">10</button> </div> </div> <script>/* code that sets up global listeners */</script> <script type="text/qwik">/* JSON representing APP_STATE, FRAMEWORK_STATE */ </script>
We can see in some tags, there is an on:click attribute which tells the JS paths. That the JS paths are encoded in HTML right on the server, the browser does not need to fetch JS files until they are required.
Moreover, there is a script tag that sets up a single global listener. This listener listens to interactions made by the user and then executes the JS file handling the corresponding event.
Resumability is different from Hydration because the browser does not re-do any work that the server did. With Resumability, the website stays lazy and does not execute tons of JS scripts at the initial loading. Executing and fetching only happen after the user trigger some events because it already knows the location of the only JS file containing the corresponding events attached in the static HTML file, unlike Hydration having to do all the fetching and binding ALL of the events in advance, resulting in a significant delay.
Lazy processing enables users to interact with SSR websites right away. While the user RESUME to use the website, the browser RESUMES to execute and add interaction to it. Furthermore, it also avoids unnecessary work. For example, on a complex website with tons of interactions, users can hardly click or interact with all of them, so Resumablity does not need to create event handlers that are never triggered, which is better than hydrating all of them.
- Understanding Hydration in React application (SSR), blog.saeloun.com, accessed August 8th, 2022.
- Hydration is pure overhead, builder.io, accessed August 8th, 2022.
- Resumable, Qwik, qwik.builder.io, accessed August 8th, 2022.