At the end of 2020, React announced a brand new feature: Server Components. At that time, it was still in the research and experimental stage and was not officially released. With the official release of React 18.0, the footsteps of Server Component are getting closer and closer. If no issue, it should be officially released in a minor version of React 18 this year.
Server Components doesn’t sound like that exciting, the numerous capabilities launched through React 18 appears to be unremarkable, and it’s been extra than 3 years considering that Hooks got here out, and React appears to have stalled its progress, simply constructing on the prevailing foundation. Do a few minor repairs?
No。
Concurrent rendering (a new feature brought by React 18) is an essential change. It does not change the development experience like Hooks, but this adjustment of the underlying rendering capability/mechanism will bring very, very Many possibilities, such as: Suspense, OffScreen, Server Components
None of these three features are currently available in production, but when they are officially released in the future and are gradually used on a large scale, each feature will bring a very significant improvement in the development experience. And if I were to pick one of the new features that will appear in the future, it would undoubtedly be Server Component.
So, what exactly are Server Components? Will he have a huge impact on the entire React ecosystem like Hooks did back then? Before we answer these questions, it is necessary to explain what Server Components are and what problems they solve.
Note: Much of what follows is inspired by this video of Dan and Lauren’s talk [1], which is highly recommended if you want to learn more about the upcoming React Server Component. In fact, this article is not A tutorial on the usage of Server Components will not cover every detail of Server Components (even some details will be deliberately omitted for convenience of expression), therefore, before reading the following, it is best to have some understanding of Server Components
Background: Separation of front and back ends
“Separation of front-end and back-end” is the current mainstream web research and development model. The back-end stores data, and encapsulates data operations (addition, deletion, modification, and query) into interfaces, which are provided to the front-end through back-end services. The front-end application sends requests (such as http requests or rpc request) to call the interface provided by the backend to obtain or modify the data.
This may be a very common R&D model for more than ten years. Therefore, we are divided into front-end development and back-end development, each responsible for the side of the “Chu River and Han World”. We have done a lot of optimization, innovation, and breakthroughs on our respective sides. On the back end, we have containerization, microservices, and SSR. On the front end, we have code spliting, front-end routing, and React Hooks.
But for the API layer, we seem to have not paid attention to it for so many years. Even if there is, it only stays in the API transmission performance (such as grpc), the existing form of the API (such as Restful and GraphQL), and the engineering management of the API (such as Postman).
Not to say that APIs are evil and badly designed, but it’s been 22 years since the concept of Restful was coined, should we rethink it now:
Is it the optimal solution to use network requests as the front-end and back-end boundaries?
How can we architect and develop web applications without an API?
The crux
Let’s go back to the picture just now and consider the problems that APIs bring in addition to the clarity of responsibilities.
Request Waterfall
As shown on the homepage of Remix [2], the front-end site based on API and nested routing will have a waterfall phenomenon when requesting:
Check the Gif here : https://blockisthenewchain.com/blocker-storage/2022/07/0134fae9515ed1c516e259af26165b0658d925.gif
There may be a front-to-back dependency between the data, or it may be strongly coupled with the component, and you need to wait for the component’s bundle to be loaded before sending the request, which leads to the appearance of the request waterfall phenomenon.
concurrent requests
The backend wants to implement small and beautiful interfaces, each with independent responsibilities, such as:
- getUser Get user information
- getSongs?page=12 Get song list
- getNotifactions Get the list of notifications
- getFavoirateSongs Get favorite songs
- getNewSongs Get newly released songs
- getRecommendSong Get today’s recommended songs and the corresponding copy
- getSearchBarHotKeywords Get popular search terms
- getAdbanner Get the content of the ad banner
- getRecentSongs Get the recent song records
- getRecommendedPlayList Get the recommended playlist list
- … (it’s too much)
Each interface is reasonable to take out separately, but put together, you will find that every time the user opens such a music web app, at least a dozen interfaces must be sent. For some slightly more complicated web pages, the first load It is not surprising that dozens of interfaces need to be requested.
Each interface request will bring network overhead, and even in some environments there will be a limit on the maximum number of concurrent requests (such as rpc requests on the Alipay client), perhaps automatic batching at the network layer can solve this problem, but unfortunately The thing is, in the current technical system, this problem is not easy to solve (it is not written here, because there are indeed some feasible solutions, such as BFF, relying on gateways for interface aggregation, but they all introduce new problems ).
Bundle size
The package size has been criticized in the field of “modern” front-end development. The js file of hundreds of kilograms seems to have deviated from the original intention of browsers to “browse” web pages. Not that we all have to be browser fundamentalists, but wouldn’t it be a good thing if web pages could be restored to a very lightweight and fast state without sacrificing user experience and development experience?
Collaboration costs (communication, logical perception and closure)
In my opinion, this is the most annoying problem in large projects or applications that require long-term maintenance.
Suppose we now have a very huge application that needs to be written and maintained by more than a dozen developers. How to divide the labor? The answer must be to do modularization first. We divide the entire application into several modules that are as independent as possible from each other, and then each person or several people are responsible for one of the modules.
The benefits of modularization are clear boundaries (you can judge which module or modules are involved when you see a requirement), clear responsibilities (everyone has their own responsibilities), and reduced communication costs (due to the internal The logic is closed and does not require external perception, so communication costs can be reduced).
For the first two points, the current front-end and back-end separation architecture is still passable, but for the third point, I think the cooperation model based on the network request interface does not effectively achieve logical internal closure and reduce the need for front-end and back-end in many cases. The amount of information communicated back and forth.
Server Components
To reiterate, the following assumes that readers and friends already know something about Server Components [3]
The API model based on network requests has a big premise that the front-end application and the back-end application are two independent applications, but why must this be the case?
Maybe we can let the backend application render HTML directly, and re-render the page when the user operates? This is actually the architecture before the Restful era. There are many drawbacks, especially poor interactivity. Otherwise, the popularity of Restful will not occur later.
Then maybe, we can make the front-end React components run on the back-end?
This is React Server Components.
A picture is worth a thousand words. In the current front-end and back-end separation mode, the back-end provides an interface, and the front-end React component calls the interface.
And if the backend can run React components and directly render the React node tree to the frontend, there is no need for the so-called API concept.
Running React components on the backend is nothing new. We have long been accustomed to SSR (Server Side Rending), but it should be noted that in SSR, the backend runs React components and generates an initial The html of the state, but this html is not interactive, it is just an improved, tinker-like optimization to allow users to see the page as soon as possible.
What Server Components brings is that we can use some of the components in the same project as Server Components and the other as Client Components, so we can enjoy the convenience and maintainability brought by internal back-end calls , while ensuring that the interactivity of the page is hardly compromised.
If you have used PHP or Django, you must be very familiar with this pattern: the backend renders the html content directly, the browser is only responsible for display, the user clicks the button, then re-request and re-render the page, if the page needs some complex Dynamic interaction, such as allowing the user to expand/collapse a list, or to display a modal after clicking a button, can be achieved with the help of jQuery.
PHP + bootstrap + jQuery, now, Server Components is like an upgraded version of this paradigm, which can be called a new “full stack” development mode.
Because it is in the back-end environment, these Server Components can use all the back-end capabilities, whether it is middleware, calls of other back-end microservices, or even db access (of course, you can run SQL directly, but it is better practice is through a data middle layer), can be achieved. In this way, we can get the data directly from the source and put it in the context of the React component, so naturally there is no need for an API in the traditional sense.
To be more precise, the API has not disappeared, and we will not actually say goodbye to the API, but let it take a different form. Where there is modularity, there will be APIs. Restful’s http network requests are APIs, but the methods exposed by middleware, the Date object provided by the browser, the file reading function provided by node, and the SQL provided by db are all is the API.
Under this new architecture, the API becomes a call between business applications and upstream services in the backend, and becomes a props transfer between Server Components and Client Components. The former makes the API cleaner and more in line with a single responsibility principle, which makes the API so natural that you can barely perceive it.
so:
- Server Components allows us to no longer split modules according to front-end-back-end, but to split modules more reasonably according to business applications-underlying services. This can theoretically reduce the communication cost between modules (because there is no way to prove it in practice).
- Since Server Components runs components on the backend and directly transmits them to the frontend for rendering through the network, many large-volume packages (such as markdown rendering, html sanitize) do not need to be downloaded and run on the frontend, thus greatly reducing the package size. .
- Since the calls to the underlying db or upstream services all happen inside the backend, even if there are concurrent requests, the overhead is far less than the frontend calling the backend’s Restful API concurrently.
- In the same way, the problem of requesting waterfall flow will disappear or be alleviated because the call overhead is reduced.
imagine
If you dare to imagine, the future development model may be like this:
Developers will no longer distinguish between front-end and back-end, but differentiate between business application development and upstream service development. The current back-end development will (really) no longer need to focus on the view logic, and only focus on the underlying business logic, providing clear, easy-to-use, atomic services/interfaces for the front-end; and the current front-end development will be extended to span the front-end And the back-end (code running environment), responsible for building the view layer based on the atomic underlying capabilities encapsulated by the back-end, and we also need a new framework and infrastructure to adapt to Server Components .
At present, Server Components has not been officially released, and even after it is officially released, there is still a long way to go. Server Components adds a lot of additional restrictions, and the distinction between server, client, and shared may also bring Some understand the cost. Caching, performance, incremental update strategy when server re-rendering, grayscale and rollback when publishing, handling of boundary conditions in business, there are still many problems to be solved, and many unknowns have not been solved. verify.