- Client-side Rendering
- Server-side Rendering
- Static Rendering
- Incremental Static Generation
- Progressive Hydration
- Streaming Server-side Rendering
- Selective Hydration
- Islands Architecture
Rendering content on the web can be done in many ways today. The decision on how and where to fetch and render content is key to the performance of an application. The available frameworks and libraries can be used to implement different rendering patterns like Client-Side Rendering, Static Rendering, Hydration, Progressive Rendering and Server-Side Rendering. It is important to understand the implications of each of these patterns before we can decide which is best suited for our application.
The Chrome team has encouraged developers to consider static rendering or server-side rendering over a full rehydration approach. Over time, progressive loading and rendering techniques by default may help strike a good balance of performance and feature delivery when using a modern framework
The following sections will provide a guideline on measuring the performance requirements for an application with respect to web rendering and suggest patterns that best satisfy each of these requirements. Subsequently, we will explore each pattern in-depth and learn how it can be implemented. We will also talk a bit about Next.js which can be used to implement these patterns. However, before we go into the available patterns or Next.js, let's take a look at how we got here and what were the drivers that resulted in the creation of the React framework and Next.js.
A brief history of web rendering
React was introduced in 2013 as a flexible framework for building user interfaces and UI components and provided a base for developing both single-page web and mobile applications. From 2015 to 2020 the React ecosystem has evolved to include supporting data-flow architecture libraries (Redux), CSS frameworks (React-Bootstrap), routing libraries and mobile application framework (React Native). However, there are some drawbacks of a pure Client-Side rendering framework. As a result, developers have started exploring new ways to get the best of both the Client-side and Server-side rendering worlds.
Rendering - Key Performance Indicators
Before we talk about drawbacks, let us understand how we could measure the performance of a rendering mechanism. A basic understanding of the following terms will help us to compare the different patterns discussed here.
|TTFB||Time to First Byte - the time between clicking a link and the first byte of content coming in.|
|FP||First Paint - First time any content becomes visible to the user or the time when the first few pixels are painted on the screen|
|FCP||First Contentful Paint - Time when all the requested content becomes visible|
|LCP||Largest Contentful Paint - Time when the main page content becomes visible. This refers to the largest image or text block visible within the viewport.|
|TTI||Time to Interactive - Time when the page becomes interactive e.g., events are wired up, etc.|
|TBT||Total Blocking Time - The total amount of time between FCP and TTI.|
Some important notes about these performance parameters are as follows.
- The time required for the first byte of content to reach the browser (TTFB) is dependent on the time taken by the server to process the request.
- Techniques such as preload, prefetch and script attributes can affect the above parameters as different browsers interpret them differently. It is helpful to understand the loading and execution priorities assigned by the browser for such attributes before using them.
We can now use these parameters to understand what exactly each pattern has to offer with respect to rendering requirements.
Patterns - A Quick Look
Client-Side Rendering (CSR) and Server-Side Rendering (SSR) form the two extremes of the spectrum of choices available for rendering. The other patterns listed in the following illustration use different approaches to provide some combination of features borrowed from both CSR and SSR.
Illustrated by Jason Miller
We will explore each of these patterns in detail. Before that, however, let us talk about Next.js which is a React-based framework. Next.js is relevant to our discussion because it can be used to implement all of the following patterns.
- Static SSR (experimental flag)
- SSR with Rehydration
- CSR with Prerendering also known as Automatic Static Optimization
- Full CSR
We have now covered four patterns that are essentially variations of SSR. These variations use a combination of techniques to lower one or more of the performance parameters like TTFB (Static and Incremental Static Generation), TTI (Progressive Hydration) and FCP/FP (Streaming). The patterns build upon existing client-side frameworks like React and allow for some sort of rehydration to achieve the interactivity levels of CSR. Thus, we have multiple options to achieve the ultimate goal of combining both SSR and CSR benefits.
Depending on the type of the application or the page type, some of the patterns may be more suitable than the others. The following chart revisits, summarizes and compares the highlights of each pattern that we discussed in the previous sections and provides use cases for each.
- Rendering on the web
- Rendering on the web - YouTube
- Next.js Docs
- Next.js fundamentals
- Code Splitting with Dynamic imports in Next.js
- Google Trends
- Client-side vs. server-side rendering
- React.js Docs
- Instant Loading Web Apps with an Application Shell Architecture
- Lazy Loading
- How to Enable Server- Side Rendering for a React App
- Fetching and Hydrating a Next.js app
- FE jargon you should know
- The case of partial hydration
- Incremental Static Regeneration with Next.js
- What is React Concurrent mode
- Whats new in Server Side Rendering in React 16
- Streaming Server Side Rendering and Caching at Spectrum