And again, hello everyone! Judging by the reactions and the number of bookmarks to the translation of the first part of the Patterns.dev book, this material turned out to be useful for you. Therefore, I decided to share the translation of the second part.
It is about rendering patterns. With the right selection, you can get faster assembly and excellent loading performance at low processing costs.
Let me remind you that the authors of Patterns.dev:
Eddie Osmani is a technical manager working on Google Chrome. His teams work on projects like Lighthouse, PageSpeed Insights, Chrome User Experience Report, and more.
The material of the book will be useful not only for React developers, but also for everyone who is interested in or encounters frontend development in one way or another. This is an introductory part of the translation of the textbook https://www.patterns.dev/. The translation of the entire second part of the textbook can be found Here.
PS: At the moment it is posted in the form of pdf, in the future a full-fledged publication on github is planned for ease of study
This adaptation is distributed under license. Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)
When you start developing a new web application, one of the main decisions you make is “How and where do I want to display content?”. Should it be rendered on the web server, build server, on Edge, or directly on the client? Should it show up all at once, partially, or gradually?
The answers to these important decisions largely depend on the use case. Choosing the most appropriate rendering pattern can make a huge difference to the developer experience (DX) you create for your engineering team and the user experience (UX) you design for end users.
Choosing the right pattern can result in faster builds and excellent loading performance at low processing costs. On the other hand, choosing the wrong pattern can kill an application that could make a great business idea a reality. So you have to make sure that every revolutionary idea you have goes into development with an appropriate rendering pattern.
The Importance of Rendering Patterns
To create a great UX, we usually try to optimize our apps for user-facing metrics like Core Web Vitals (CWV). CWV metrics measure the parameters most important to the user experience. CWV optimization can help provide a great user experience and optimal SEO for our apps.
In order to create great DX for our product/engineering teams, we need to optimize our development environments with faster build times, easy rollback, scalable infrastructure, and many other features that help developers succeed.
Setting up a development environment based on these principles enables our development teams to build great products efficiently. Summing up our expectations, we have made a rather long list. But, if you choose the right rendering pattern, you can get most of these benefits out of the box.
Rendering patterns have come a long way from Server Side Rendering (SSR) and Client Side Rendering (CSR) to nuanced patterns being discussed and judged in various forums today. While it may seem overwhelming, it’s important to remember that each pattern was designed for specific use cases. A characteristic of a pattern that is beneficial for one use case may be detrimental to another. It is also likely that different page types require different rendering patterns on the same website.
The Chrome team has urged developers to consider static or server-side rendering instead of a full rehydration approach. Over time, progressive loading and default rendering methods can help find a good balance of performance and feature delivery when using a modern platform. The following chapters detail the various patterns, old and new. But first, we’ll briefly introduce some of them to help you understand where they work best.
Static rendering is a simple yet powerful pattern that you can use to create fast websites with almost instantaneous page loads. With static rendering, the HTML for the entire page is generated at build time and does not change until the next build. HTML content is static and easily cached on a CDN or edge network. CDNs can quickly serve pre-rendered cached HTML to clients when they request a particular page. This greatly reduces the time it would otherwise take to process the request, render the HTML content, and respond to the request in a typical server-side rendering setup. The above process is best for pages that change infrequently and display the same data no matter who requests it. Because we consume a lot of dynamic, customizable data on the web today, we have flavors of static rendering for a variety of use cases.
Basic/simple static rendering
Since there are many variations of static rendering, let’s call the main method we discussed earlier simple static rendering. You can use it for pages with little or no dynamic content.
Normal static rendering is great for performance as it results in an extremely fast TTFB since the HTML is already available on the server. The browser gets a faster response and can render it quickly, resulting in fast FCP and LCP. Since the content is static, no layout shift occurs when it is rendered.
Thus, simple static rendering, especially using a CDN for caching, helps achieve great Core Web Vitals. However, most websites have at least some dynamic content or user interaction.
Client side static rendering fetch
Let’s say we want to improve our property demo to display the most recent property listings. We would have to use a data provider to get these lists.
In this case, we can use static rendering with fetch on the client side. This pattern works great when you want to update data on every request.
You can still use static rendering for a website to render the UI with a skeletal component where you want to place the dynamic list data. Then, after the page is loaded, we can retrieve the data (using SWR, for example) on the client.
The custom API route is used to retrieve data from the CMS and return that data.
The pre-generated HTML file is sent to the client when the user requests the page. First, the user sees the UI wireframe without any data. The client fetches the data from the API route, receives the response, and renders the lists. (the hydration call is not included in the example) gives the answer and shows the lists (the hydration call is not included in the example).
While static rendering with client-side fetch gives us good TTFB and FCP, LCP is sub-optimal because “largest content” can only be rendered after we get the list data from the API route.
There is also a high chance that the layout will change, especially if the size of the UI wireframe does not match the content that is ultimately displayed. Another downside is that this approach can result in higher server overhead since we are calling the API route once for every page request. Next.js offers some solutions, described in the following sections, to improve the performance of your application when working with dynamic data.