I. SSR Introduction

SSR (Server-Side Rendering) is not a novel concept. For a long time before the separation of frontend and backend, server-side rendering was dominant (JSP, PHP), generating complete HTML pages on the server.
Excerpted from Exploration of Frontend Rendering Modes
The reason to complete component rendering work on the server is because of two major advantages: performance and accessibility.
II. 2 Major Advantages
Performance
Compared with CSR (Client-side rendering) mode, SSR's performance advantages are reflected in 2 aspects:
-
Network link
-
Saves network transmission overhead of client's second request for data
-
Server's network environment is superior to client's, communication path between internal servers is also shorter
-
-
Content presentation
-
First screen loading time (FCP) is faster
-
Browser content parsing optimization mechanisms can play their role
-
On the network link, API requests are sent from the server, returned data is passed to the client together with HTML response content in one go, faster than CSR's second request. And server's network transmission speed is faster (can have larger bandwidth), communication path is shorter (can be deployed in same data center), communication efficiency is also higher (can use RPC).
In terms of content presentation, CSR's HTML is mostly an empty shell:
<!DOCTYPE html>
<html>
<head>
<title>My Awesome Web App</title>
<meta charset="utf-8">
</head>
<body>
<div id="app"></div>
<script src="bundle.js"></script>
</body>
</html>
Client receiving this kind of HTML can only immediately render a blank page, can only present meaningful content after second request's data comes back, while SSR's returned HTML has content (data), client can immediately render meaningful first screen content (First Contentful Paint). At the same time, static HTML documents let streaming document parsing and other browser optimization mechanisms also play their role.
Key difference is SSR doesn't depend on client environment, including network environment and device performance, that is even if user's network situation is very bad (weak network), device performance is very poor (cheap, old devices), server-side rendering can still guarantee content loading experience similar to optimal user environment (Wi-Fi network, high-end devices).
Accessibility
Accessibility is understood from 2 aspects:
-
For people: Old, special user devices, such as JavaScript disabled
-
For robots: Crawler programs, etc., typically, search engine crawlers
The former generally doesn't need to be too concerned, the latter needs to focus on two major "customers":
-
Search engines: SEO
-
Social media: Crawl page content to display thumbnail information (such as Twitter cards, etc.)
For PC sites, ensuring search engines can correctly index and accurately understand page content has important commercial value (search results rank higher, greater exposure). Mobile side doesn't need to consider search engine crawling, but also has similar social sharing needs, social media will crawl images and other content from target pages as thumbnail information.
P.S. Admittedly, some search engines can correctly crawl heavy CSR SPAs, but not all, and a large number of social media mostly only extract partial content from response HTML as thumbnail information, the demand for dynamically rendering HTML (partial) content truly exists.
Although having these advantages, SSR is far less widely used than CSR, because SSR faces 6 major challenges.
III. 6 Major Challenges
Challenge 1: How to Leverage Existing CSR Code to Achieve Isomorphism
For purposes of degradation, reuse, reducing migration costs, etc., usually adopt isomorphic approach where one set of JavaScript code runs across client and server to implement SSR, however, to make existing CSR code run on the server, first need to solve many problems, such as:
-
Client dependencies: Divided into API dependencies and data dependencies, such as JS APIs like
window/document, device-related data information (screen width/height, font size, etc.) -
Lifecycle differences: For example, in React,
componentDidMountis not executed on the server. -
Asynchronous operations not executed: Server-side component rendering process is synchronous,
setTimeout,Promise, etc. cannot be waited for. -
Dependency library adaptation: React, Redux, Dva, etc., and even third-party libraries with uncertainty about whether they can run in universal environment, whether state needs to be shared across environments, taking state management layer as an example, SSR requires its store to be serializable.
-
Shared state on both sides: Every piece of state that needs to be shared must consider how to pass (server-side) and how to receive (client-side).
Challenge 2: Service Stability and Performance Requirements
Compared with client-side programs, server-side programs have much stricter requirements for stability and performance, for example:
-
Stability: Abnormal crashes, infinite loops
-
Performance: Memory/CPU resource usage, response speed (network transmission distance, etc. must be considered)
Therefore facing backend professional problems, Demo-level SSR may not be difficult, but highly available SSR service is by no means easy, how to handle high traffic/high concurrency, how to identify failures, how to degrade/quickly recover, which links need caching, how to update cache...
Challenge 3: Construction of Supporting Facilities
The core part of SSR is the rendering service, but in addition, consider:
-
Local development kit (validation + build + preview/HMR + debugging)
-
Release process (version management)
A whole set of engineering facilities needs to be reconsidered in SSR mode.
Challenge 4: The Money Problem
Introducing SSR rendering service actually adds a layer of nodes to the network structure, and wherever high traffic passes, every layer costs money:
Most importantly, SSR React apps cost a lot more in terms of resources since you need to keep a Node server up and running.
Moving component rendering logic from client to server execution, computing resource costs must be considered.
Challenge 5: Performance Loss of Hydration
After client receives SSR response, in order to support (JavaScript-based) interaction functions, still needs to create a component tree, associate it with HTML rendered by SSR, and bind related DOM events to make the page interactive, this process is called hydration.
JavaScript code that hydration needs to load and execute is not much less than CSR mode, this part of work is executed on client side, limited by user device's performance, under poorer devices may cause perceptible non-interactive time:
-
CSR: Interactive but no data (still asynchronously requesting data, may last very long)
-
SSR: Has data but not interactive (after pulling JS, during hydrate process, can see content but not interactive, generally won't last very long)
Under rich interaction scenarios, the latter is not necessarily better user experience than the former.
Challenge 6: Data Requests
Server-side synchronous rendering requires sending requests first, and only starts rendering components after getting data. So there are 3 problems:
-
Data dependencies must be stripped from business components
-
Missing client public parameters (including header information like cookie that the client will carry by default)
-
Different data protocols on both sides: The server may have more efficient communication methods, such as RPC.
Under current mainstream CSR mode, data dependencies and business components are tightly coupled, data requests that must be initiated from server are all mixed in component lifecycle functions, stripping data dependencies means needing to simultaneously transform CSR code. Differences in public parameters, data protocols, etc. also pose some new challenges for code reuse and maintainability.
IV. Application Scenarios
Whether first screen loading performance or accessibility, both are only meaningful for content-intensive pages, and for interaction-intensive pages, SSR can render content in advance not much, not much significance to users, SEO necessity is also worth discussing. Therefore, SSR is suitable for relatively static content display scenarios, typically, product details, guides, articles and other text-image mixed arrangement scenarios.
On the other hand, doesn't necessarily need 100% SSR, rendering specific pages, or even just rendering a page framework is also a good application:
"Application Shell" is an excellent concept. But sometimes, we might need to render a part of the page in the server. It could be the header with user info. In such cases, you need server-side rendering.
References
- A PAIN IN THE REACT: CHALLENGES BEHIND SSR
- Why it's tricky to measure Server-side Rendering performance: Angular SSR and CSR comparison actual measurement, data can be referenced
- Hey Next.js, Is Server Side Rendering Dead?
No comments yet. Be the first to share your thoughts.