Skip to main content

Command Palette

Search for a command to run...

翻譯筆記 - Next.js: 網頁渲染的終極 Cheat Sheet

翻譯自 https://medium.com/@gdumais/next-js-the-ultimate-cheat-sheet-to-page-rendering-46e4f82ce1ee

Published

I am not a programmer just a leaner. Writing JavaScript, Python, and Go and doing something on Kubernetes.

Next.js 有四種渲染策略

  • Static-Site Generation (SSG)
  • Server-Side Rendering (SSR)
  • Incremental Static Regeneration (ISR)
  • Client-Side Rendering (CSR)

此外,這 Cheat Sheet 清楚地展示每種策略會如何影響 Core Web Vitals 指標:TTFB、FP、FCP、LCP、TBT 和 TTI。

Next.js: The Ultimate Cheat Sheet to Page Rendering

從 Cheat Sheet 的左側可以發現從 Build 到渲染給 Client 端,會經過六個步驟。右側的話可以知道不同步驟在 Server 或 Client 的處理流程中發生的位置。每個策略列可以看到不同的步驟中的執行內容。還能知道每個步驟中看到稱成的內容(HTML - React/CSS/JavaScript/Data)。

在此篇文章中,作者有提供一個 Live Demo 的網頁。(但有些我看不太出來差異,要搭配開發者工具去比較比較清楚)

Static-Site Generation (SSG)

此策略是 Next.js 的預設策略。Next.js 推薦使用此策略達到最好的效能,產生可讓 CDN 使用的靜態內容,而達到更快的 Time to First Byte(TTFB)

Step 1

Next.js 在 HTML 中生成一個 Single Page App 以及伺服器上的 .css.js。此步驟稱為 pre-rendering,只會在下一個 build 指令執行時,執行一次。在此步驟中,所有網頁的程式(HTML) 都會生成,包括 React、CSS、JavaScript 以及所需的資料(如果網頁使用任何資料取得方法,例如 getStaticProps()getStaticPaths()

Step 2

Client 從 CDN 請求 Single Page App

Step 3

Client 從 CDN 下載 Single Page App

Step 4

Client 解析並渲染 Single Page App 到瀏覽器中。 這是觸發三個 Core Web Vitals 指標的地方(First Paint、First Contentful Paint 和 Largest Contentful Paint)。因為網頁的 HTML 已經在伺服器渲染,所以 Client 瀏覽器只需要按原樣載入和渲染。而且由於網頁的編碼方式允許瀏覽器使用最少的 JavaScript 呈現,因此可以將 render-blocking 的影響減少到最低限度,從而得到很好的效能。

Step 5

React(JavaScript)程式碼會以 (re)Hydrate 網頁。即使網頁已經 pre-built,也需要這個額外的步驟來讓 React 將 JavaScript 添加或啟用到 Virtual DOM 使其網頁有互動性。因為此時執行 JavaScript,所以所有的渲染阻塞時間都受此額外步驟影響。此外,由於瀏覽器必須等待 hydration 過程完成,因此互動時間也會受到影響

TypeScript 範例

// Next.js libraries
import Head from 'next/head';

// Custom Components
import BackToHome from 'components/BackToHome';

// Page component
export default function StaticSideGeneration({ jsonData }) {
    return (
        <>
            <Head>
                <title>Static-Site Generation (SSG) • Guy Dumais</title>
                <meta
                    name='description'
                    content='Example page using Static-Site Generation (SSG) with Next.js 11 and React 17'
                />
                <meta
                    name='viewport'
                    content='initial-scale=1.0, width=device-width'
                />
            </Head>
            <BackToHome />
            <h1>Static-Site Generation (SSG)</h1>
            <p>
                Data fetched at build-time on the server-side before sending to
                the client.
            </p>
            <ul>
                {jsonData.data.map((e) => (
                    <li key={e.id}>{e.email}</li>
                ))}
            </ul>
        </>
    );
}

// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries.
export async function getStaticProps() {
    const res = await fetch('https://reqres.in/api/users?page=2');
    const jsonData = await res.json();

    return {
        props: {
            jsonData, // will be passed to the page component as props
        },
    };
}

Server-Side Rendering (SSR)

Server-Side Rendering 是 Next.js 提供的第二種產生網頁的策略。Next.js 建議盡可能地避免使用此策略,因為靜態內容只針對每個請求 built(pre-rendered)和 distributed。所以建制過程需要額外的時間,Time to First Byte (TTFB) 指標會增加從而導致不好的結果。

Step 1

在此步驟 Next.js 不會產生(pre-render)任何網頁

Step 2

Client 向伺服器請求 Single Page App,Next.js 在 HTML 檔案中產生(pre-render)一個 Single Page App 和其所需的 .css.js。在此步驟中,所有的網頁程式碼(HTML)都會產生,包括 React、CSS、JavaScript 以及所需的資料(如果網頁使用 getServerSideProps() 來獲取資料)

Step 3

Client 從伺服器下載 Single Page App

Step 4

和 SSG 第四步驟一樣

Step 5

和 SSG 第五步驟一樣

TypeScript 範例

// Next.js libraries
import Head from 'next/head';

// Custom Components
import BackToHome from 'components/BackToHome';

// Page component
export default function ServerSideRendering({ jsonData }) {
    return (
        <>
            <Head>
                <title>Server-Side Rendering (SSR) • Guy Dumais</title>
                <meta
                    name='description'
                    content='Example page using Server-Side Rendering (SSR) with Next.js 11 and React 17'
                />
                <meta
                    name='viewport'
                    content='initial-scale=1.0, width=device-width'
                />
            </Head>
            <BackToHome />
            <h1>Server-Side Rendering (SSR)</h1>
            <p>
                Data fetched on the server-side at <b>each</b> request before
                sending to the client.
            </p>
            <ul>
                {jsonData.data.map((e) => (
                    <li key={e.id}>{e.email}</li>
                ))}
            </ul>
        </>
    );
}

export async function getServerSideProps() {
    const res = await fetch('https://reqres.in/api/users?page=2');
    const jsonData = await res.json();

    return {
        props: {
            jsonData, // will be passed to the page component as props
        },
    };
}

Incremental Static Regeneration (ISR)

Next.js 的第三個策略,此策略除了可以在網頁更新時 rebuilt 之外,其餘的都跟 Static Site Generation 一樣。

Step 1

與 SSG 第一步驟一樣

Step 2

Client 從 CDN 請求 Single Page App。此外,如果網頁使用取得資料方法 getStaticProps() 來和 revalidate 選項結合使用。如果取得回傳的資料並更新,則會重新產生網頁。Next.js 建議使用此方法在超過 1,000 個網頁的大型網站。因爲 pre-render 每個網頁都需要時間,所以使用此方法只會在第一次請求或是網頁內容更新時 pre-render。

Step 3

與 SSG 第三步驟一樣

Step 4

與 SSG 第四步驟一樣

Step 5

與 SSG 第五步驟一樣

TypeScript 範例

// Next.js libraries
import Head from 'next/head';

// Custom Components
import BackToHome from 'components/BackToHome';

// Page component
export default function IncrementalStaticGeneration({ jsonData }) {
    return (
        <>
            <Head>
                <title>
                    Incremental Static Regeneration (ISR) • Guy Dumais
                </title>
                <meta
                    name='description'
                    content='Example page using Incremental Static Regeneration (ISR) with Next.js 11 and React 17'
                />
                <meta
                    name='viewport'
                    content='initial-scale=1.0, width=device-width'
                />
            </Head>
            <BackToHome />
            <h1>Incremental Static Regeneration (ISR)</h1>
            <p>
                Data fetched at build-time on the server-side and rebuilt when
                data updated.
            </p>
            <ul>
                {jsonData.data.map((e) => (
                    <li key={e.id}>{e.email}</li>
                ))}
            </ul>
        </>
    );
}

// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// revalidation is enabled and a new request comes in
export async function getStaticProps() {
    const res = await fetch('https://reqres.in/api/users?page=2');
    const jsonData = await res.json();

    return {
        props: {
            jsonData, // will be passed to the page component as props
        },

        // Next.js will attempt to re-generate the page:
        // - When a request comes in
        // - At most once every second
        revalidate: 100, // In seconds
    };
}

Client-Side Rendering (CSR)

Next.js 的第四個策略,除了部分內容可以在 Client 建立之外,其餘的都跟 Static Site Generation 一樣。

Step 1

與 SSG 第一步驟一樣,不同的地方在於內容(資料) 既不 pre-render 也不包含在 static bunch。這將產生更小的檔案大小,因此可能縮短下載時間。

Step 2

與 SSG 第二步驟一樣,但是不包含內容(資料)

Step 3

與 SSG 第三步驟一樣,但是不包含內容(資料)

Step 4

與 SSG 第四步驟一樣

Step 5

與 SSG 第五步驟一樣,但是不包含內容(資料)

Step 6

Client 獲得內容(data)並且 React 更新 UI。此方法很有用,例如,當想要顯示具有靜態內容的骨架網頁,然後將資料逐步注入到網頁,需要長時間等待資料回傳。

TypeScript 範例

// React
import { useEffect, useState } from 'react'

// Next.js
import Head from 'next/head'
import Link from 'next/link'

// Custom Components
import BackToHome from 'components/BackToHome'

// Page component
export default function ClientSideRendered() {

    const [state, setState] = useState([] as any)

    const getData = async () => {
        const res = await fetch('https://reqres.in/api/users?page=2')
        const jsonData = await res.json()
        setState(jsonData)
    }

    useEffect(() => {
        getData()
    }, [])

    return (
        <>
            <Head>
                <title>Client-Side Rendering (CSR) • Guy Dumais</title>
                <meta name="description" content="Example page using Client-Side Rendering (CSR) with Next.js 11 and React 17" />
                <meta name="viewport" content="initial-scale=1.0, width=device-width" />
            </Head>
            <BackToHome />
            <h1>Client-Side Rendering (CSR)</h1>
            <p>Data fetched on the client-side only.</p>
            <ul>
                {
                    state.data?.map((e) => (
                        <li key={e.id}>{e.email}</li>
                    ))
                }
            </ul>
        </>
    )
}

More from this blog

如何開始入門軟體工程領域 - 名詞解釋(長期更新)

現在應該開始有很多人想要踏入軟體工程的領域,但在進入這個領域之前,覺得先了解一些名詞,可以在入門時更有方向也更知道要用什麼關鍵字去找尋有用的資訊。這篇文章就是想要幫助想要入門的人理解一些軟體工程裡的專有名詞。 作業系統 這一區塊主要解釋跟作業系統層面相關的名詞 英文中文解釋 Operation system 簡稱 OS | 作業系統 | 就是電腦的作業系統,是三大作業系統分別是:Linux、Windows、macOS | | Linux | | 自由和開放原始碼的 UNI...

May 10, 2023

我的 MacBook Pro (Apple Silicon) 設定

現在開始因為 ChatGPT 的出現,各種 AI 助手的功能都跑出來了。想想自己用了許久的環境設定也應該要來重新審視和建立新的開發環境了,僅此紀錄我個人的環境配置步驟和設定。 環境前置步驟 還原 MacBook Pro 至全新環境 macOS(全部資料刪除) 設定好初始設定後,登入 Apple ID 進入 App Store 確定 macOS 版本和預設 APP 都更新到最新 macOS 版本 到系統設定調整所有設定至個人習慣的設定 三指拖移 觸控板手勢開啟 防火牆開啟 輸入法設定...

Apr 25, 2023

ChatGPT 下的發展預想

從 ChatGPT 問世到現在,有許許多多的文章和討論出來。先從最早的 Google 要完蛋了,到後來的工作要被取代了,工程師失業了。 我就比較沒有想要馬上出來評論一下,我喜歡讓子彈飛一會兒。跟討論一下我自己比較在意的討論點。 Google 為什麼慢了? 結論:因為他需要更小心 很多人說 Google 怎麼被微軟搶先了一步。剛開始 Bing 說要加上 AI 的時候大家都在說 Google 怎麼慢了。我就馬上跑去看 OpenAI 的網站,靠北呀啊就 Azure 贊助的。那當然在正式上線 ChatG...

Mar 23, 2023

不工程的攻城獅

223 posts

I am not a programmer because I am not good at programming. But I do programming. Love to learn new things. An animal lover and a dancer. My oshi is 潤羽るしあ.