SSR, CSR, SSG, ISR and DPR technologies in Next.js

CSR (Client Side Rendering) client rendering

CSR is client-side rendering, such as the common rendering method used by SPA, which is supported by all mainstream frameworks , or in other words: as long as JS is used in the client-side rendering process, and the data is obtained and rendered through the client sending a request, it can be counted as client-side rendering.

CSR main flow chart

It is also very simple to use client-side rendering in Next.js, as long as the above-mentioned APIs, such as getStaticProps, getServerSideProps< /strong> …are not used. The data is obtained and rendered by sending requests using axios or fetch inside the component. Then we use pure client-side rendering, which is no different from using Vue or React directly. So there is actually no need to create a separate service to do this.

Take the packaged and compiled HTML of the React project as an example

<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <link rel="icon" type="image/svg + xml" href="/vite.svg" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>React App</title>
   <script type="module" crossorigin src="/assets/index-c7e05d32.js"></script>
   <link rel="stylesheet" href="/assets/index-d526a0c5.css">
 </head>
 <body>
   <div id="root"></div>
 </body>
</html>

You can clearly see that there are only

elements in the page content, and no other elements. Then load index-c7e05d32.js, index-d526a0c5.css to perform rendering. The entire rendering process includes generating DOM nodes, injecting styles, binding interactive events, obtaining data, etc.

  • advantage

  1. The pressure on the server has been reduced, allowing the rendering work to be performed on the client. The backend focuses on API development, with true front-end and back-end separation. The server directly returns unprocessed HTML.

  2. Users have a good experience in subsequent visits (the first screen rendering is slow) and the website can be made into a SPA, which can be rendered incrementally

  • shortcoming

  1. It is not conducive to SEO because the search engine does not perform JS related operations and cannot obtain the final rendered html.

  2. The first screen rendering time is relatively long because most of the tasks related to the web page life cycle are handled by JS, which results in poor first content paint (FCP) and time to interaction (TTI) of the page. Depending on the complexity and size of the application, this can add more time. This means that the user sees almost nothing in the time between first draw (FP) and FCP.

SSR (Server Side Rendering) server side rendering

SSR is server-side rendering, which refers to rendering the page into HTML on the server side and then returning it to the client.

SSR Main flow chart

In Next.js, if SSR is enabled, the page will be regenerated on every request. To enable SSR, we can expose an asynchronous function getServerSideProps in the file that defines the component. This method is similar to getStaticProps, but the timing of execution is different. getServerSideProps will be called every time the page accepts a request.

According to the calling timing of getServerSideProps, we can know that this method is suitable for displaying data that needs to be updated frequently. Here is an official example:

export default function Page({ data }) {
  // Render data...
}

// This method will be called every time a request is made
export async function getServerSideProps() {
  // Get data from external API
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  // Pass data into the component through props
  return { props: { data } }
}

Except for the timing of the call, getServerSideProps is no different from getStaticProps, so it is easy to understand.

  • advantage

  1. It is conducive to SEO, the page content is generated on the server, and the search engine directly crawls the final page results.

  2. It is beneficial to the first screen rendering. The data required for HTML is processed on the server to generate HTML, and the first screen rendering time is shortened.

  • shortcoming

  1. Rendering is done on the server side, occupying server-side resources and causing increased pressure on the server-side.

  2. Page interaction/jumping will cause the entire page to refresh, resulting in a poor experience.

  • Application scenarios

  • For purposes such as first screen opening speed, user experience, SEO etc., it is necessary to allow users to see the first screen content of the page faster

  • There is dynamic content in the page content that you want to pre-render.

SSG (Static Site Generation) static site generation

SSG is static site generation. When building, the result page is directly output to the disk as HTML, and the HTML is directly returned to the client every time it is accessed, which is equivalent to a static resource.

SSG Main flow chart

Static website generation in Next’s is generally divided into three situations:

1. Pure static page does not need to rely on external data

function About() {
 return <div>About</div>
}

export default About

This case is the simplest. Next.js will directly generate a static HTML when packaging.

2. The content of the page relies on external data

export default function Blog({ posts }) {
  // Render article...
}
// This function will receive requests during build
export async function getStaticProps() {
  //Request API to get article data
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // When building, the Blog component can receive the posts props
  return {
    props: {
      posts,
    },
  }
}

In order to get external data during pre-rendering, we can expose an asynchronous function getStaticProps in the file that defines the component. When packaging the page, Next.js will First perform the operations in getStaticProps, such as sending requests, data processing, etc.

We can then return an object where the value of the props field will be passed in as props when rendering the component, In this way, data can be obtained from the outside during construction.

3. The path of the page depends on external data

In Next.js, routing is driven by the file system. Each page corresponds to a file, and the path of the file is the routing path of the page. For example, pages/index.js corresponds to the root path /, pages/about. js corresponds to the /about route.

Dynamic routing can be used when pages need to be generated dynamically. Dynamic routing allows the use of parameters in the routing path that can dynamically generate pages based on values in the URL. For example, you can create a dynamic route /posts/[id] to display article details with different id values page.

But when using dynamic routing, what valid parameter values does Next.js need to know (such as the article’s id) in order to pre-render?

To solve this problem, Next.js provides a special method getStaticPaths, which you can use in page components to declare a list of parameter values that need to be pre-rendered.

In the page component, if you want to use dynamic routing, you can implement the getStaticPaths method. This method returns an object containing a paths array, which contains all parameter values that need to be pre-rendered. For example, for /posts/[id], there may be multiple different post id that need to be pre-rendered, These id values will be included in the paths array.

When a user accesses a dynamic routing page, Next.js will pre-generate a static HTML file based on the parameter value list provided by the getStaticPaths method and cache it. In this way, subsequent requests for the same article will directly return pre-rendered static content, improving page loading speed and performance.

    • advantage

  1. The performance is excellent. The generated HTML files can be placed on CDN, which can also improve cache utilization.

  2. It is beneficial to SEO, because the html has been generated in advance, and there is no need for server and client to render.

  • shortcoming

  1. Generating large amounts of HTML files during build can be challenging and time-consuming.

  2. Any data updates require the application to go through the build process to generate the page again with the latest data – a very bad experience!

  3. Not suitable for highly dynamic content, only suitable for static data

  • Application scenarios

    Therefore, it is often used in scenarios with a lot of static content such as content generation through CMS and blog sites.

  1. Regarding first screen speed, user experience, SEO and other considerations, it is necessary to allow users to see the first screen content of the page faster.

  2. Static content or low-level dynamic content or more prescribed dynamic content is appropriate.

ISR (Incremental Static Regeneration) incremental static regeneration

ISR is a technology used to generate static web pages. It is widely used in modern static website generators and frameworks, aiming to improve the efficiency and performance of website generation.

ISR Main flow chart

ISRsolve the problem that SSG is not suitable for highly dynamic content. Here’s how it works:

  1. Initial generation: When building a static website for the first time, all pages will be generated.

  2. Incremental generation: Each time subsequent content updates, ISR will only regenerate the portion of the page that changed, not the entire site. This means that only the affected pages will be regenerated, other pages will remain unchanged.

  3. Caching: The generated page will be cached. When the user requests the page, it will be obtained directly from the cache, thus avoiding repeated generation process and improving the response speed of the website.

From the ISR flow chart, compared with SSG, only the Server side is added The logic is processed as follows:

  1. When the server receives the corresponding page request, the server will first return the current content and then perform invalidation verification on the page.

  2. If the page is implemented, the server will perform a background incremental build of the failed page.

  3. When the next request arrives, if the new page has been generated successfully, the content of the new page will be returned, but before that, the content of the old page will continue to be used. Of course this is not absolute,

To enable ISR in Next.js, you only need to return a getStaticProps function introduced earlier. >revalidate attribute, here is an official example:

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

// This method will be called during server-side rendering or build
// It will also be called again when the serverless function is used, revalidate is turned on and a new request is received.
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },

    // Next will try to regenerate the page:
    // - New request received
    // - every up to ten seconds
    revalidate: 10, // unit is seconds
  }
}

// This method will be called during server-side rendering or build
// When the serverless function is used, the path has not been generated and will be called again.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Get the path we want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // At build time, we will only prerender the paths in paths
  // { fallback: 'blocking' } Perform server-side rendering on demand when the page does not exist.
  return { paths, fallback: 'blocking' }
}

export default Blog

ISR is implemented by marking certain pages as ISR ready. These pages are generated identically to SSG pages, but they also have a “revalidate” time. This time tells Next.js when it needs to regenerate the page.

So we can simply summarize the incremental generation as: “Traditional pre-rendering requires regenerating HTML for all pages if the content needs to be updated, while incremental generation allows us to individually set certain pages to regenerate. Generate”, which can save a lot of unnecessary performance expenses.

  • advantage

  1. Has all the advantages of SSG and it reduces the build time of your application because it avoids pre-rendering all pages during the build.

  2. If there are any updates to the data, the page is regenerated without rebuilding the entire application.

  • shortcoming

  1. For pages that are not pre-rendered, the user will see a fallback page for the first time. At this time, the server will start rendering the page until the rendering is completed. This leads to inconsistencies in user experience.

  2. For pages that have been pre-rendered, users load them directly from CDN, but these pages may have expired, or even expired for a long time, and can only be seen after the user refreshes once and visits for the second time. new data. For scenarios like e-commerce, this is unacceptable (for example, the product has been sold out, but the expired data seen by the user shows that it is still available).

Regarding the pros and cons of ISR, you can refer to this article by Netlify: Incremental Static Regeneration: ItsBenefitsAndItsFlaws (https://www.netlify.com/blog /2021/03/08/incremental-static-regeneration-its-benefits-and-its-flaws/)

  • Application scenarios

    You can use non-trading commodity platforms that do not have high real-time requirements, such as news/information, blogs, social media, etc.

DPR (Distributed Persistent Rendering) distributed continuous rendering

DPR is a distributed persistent rendering technology for rendering images or animations on multiple computers. This technology uses the processing power and storage capacity of multiple computers to distribute rendering tasks to different computer nodes. These nodes communicate through the network and collaborate to complete rendering tasks. Since rendering tasks usually require large amounts of computing and storage resources,DPR technology can significantly improve rendering efficiency and speed.

In order to solve a series of problems with ISR, Netlify launched a new proposal some time ago: Distributed PersistentRendering(DPR)(https://github.com/jamstack/jamstack .org/discussions/549)

DPR essentially makes several changes to the ISR model and combines it with the capabilities of CDN:

  1. Removed the fallback behavior, but directly used the On-demand Builder (on-demand builder) to respond to the page without pre-rendering, and then Cache results to CDN;

  2. When the data page expires, it no longer responds to the expired cached page. Instead, CDN returns to the source Builder to render the latest data;

  3. Automatically clear CDN‘s cached data every time a new version is released.

On the Netlify platform, you can define a Builder like this for pre-rendering or real-time rendering. This Builder will run on the platform as a Serverless cloud function:

const { builder } = require("@netlify/functions")

async function handler(event, context) {

  return {
    statusCode: 200,
    headers: {
      "Content-Type": "text/html",
    },
    body:`
    <!DOCTYPE html>
      <html>
        <body>
          Hello World
        </body>
    </html>
    `,
  };
}

exports.handler = builder(handler);

More details can be found in the documentation:

on-demand-builders(https://docs.netlify.com/configure-builds/on-demand-builders/)

    • shortcoming

  1. New page access may trigger On-demand Builder to render synchronously, resulting in a longer response time for the current request;

  2. DoS attacks are difficult to defend against because attackers may visit a large number of new pages, causing Builder to be run in parallel. This requires the platform to implement Builder of normalization and serial running.

Summarize

The technology itself is not perfect. CSR, SSR, SSG, ISR, DPR These solutions have more or less problems that they cannot solve. They are essentially balancing dynamics and rendering performance. , cache performance, these three contradictions still need to continue to be explored and evolved. As technology continues to develop, there may be better solutions in the future.