網頁前端畫面渲染(Rendering)方式介紹:SSR/CSR/SSG/ISP

網頁渲染(Rendering)是將 HTMLJavaScript、資料等代碼,轉換為使用者肉眼可見網頁畫面的過程。

從網頁開發的角度中,渲染通常涉及將資料和網頁模板結合,生成最終顯示在瀏覽器中的 DOM(Document Object Model)結構。

渲染的方式有很多,雖然對使用者而言都大同小異,都是點擊網頁後,等待頁面載入後看到畫面。但不同渲染方式背後的處理邏輯、影響卻大不相同。

渲染處理得好不好,會直接影響到UX、SEO 與伺服器效能

  • UX:影響頁面載入速度、初始畫面顯示速度,從而影響用戶的使用體驗。
  • SEO:搜尋引擎爬蟲如何檢索和索引網站內容,會直接受到網頁渲染模式的影響。
  • 伺服器效能:正確選擇渲染方式能降低伺服器負擔,並加快頁面的載入速度。

目前在網頁開發上,主要有 4 種頁面渲染技術, 每種方式在資料傳遞與適用情境上都略有差異。

渲染方式全名中文名稱
CSRClient-Side Rendering客戶端渲染
SSRServer-Side Rendering伺服器端渲染
SSGStatic Site Generation靜態網站生成
ISRIncremental Static Regeneration增量靜態重新生成

本文會介紹以上提及的 4 種渲染方式,並且以 React 框架開發網頁為範例說明。

客戶端渲染 CSR

CSR(Client-Side Rendering)將所有的渲染工作交由瀏覽器(客戶端)進行,伺服器僅提供一個基礎的 HTML 文件,瀏覽器通過 JavaScript 動態渲染呈現畫面,能透過 API 取得資料,並且更新頁面內容。

CSR 的特色是能對於伺服器的負擔較小,可以將部分的網頁載入需求分配給瀏覽器完成,因此對瀏覽器負擔較大,畫面的載入時間也會相對較慢。

由於多數的網路爬蟲、搜尋引擎爬蟲都是直接透伺服器跟網站 request 網頁資料,直接透過對方 response 的內容分析網頁。因此 CSR 的內容對爬蟲程式較不友善,

如果有規劃要做 SEO,使用 CSR 開發的網站就需要使用額外的預渲染 (Pre-rendering)或 SSR 技術輔助。

Google 官方表示過數次,他們的搜尋引擎爬蟲 Googlebot 能讀懂 CSR 製作的頁面。但實際觀察下來, CSR 的頁面普遍檢索效率較差,難有很好的 SEO 表現。

CSR 的渲染步驟

CSR 頁面渲染過程
  1. 用戶請求 HTML 文件。
  2. 伺服器回傳基本的 HTML 結構(通常只有一個空的 <div id='root'> 容器)。
  3. 瀏覽器載入 JavaScript 資源,在瀏覽器端啟動,通過 API 獲取資料。
  4. JS 在客戶端生成 DOM 結構,渲染頁面
  5. 用戶最終看到完整的頁面內容。

React.js 實現動態渲染

my-app/
├─ public/
│   ├─ index.html    # 僅有一個基本的 HTML 容器
├─ src/
│   ├─ App.js        # React 主組件
│   ├─ index.js      # React 應用入口
│   ├─ components/   # UI 元件
│   ├─ pages/        # 應用頁面

public/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>CSR Example</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

src/index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

src/App.js

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

const App = () => {
    const [data, setData] = useState(null);

    useEffect(() => {
        fetch('https://jsonplaceholder.typicode.com/posts/1')
            .then((response) => response.json())
            .then((data) => setData(data));
    }, []);

    if (!data) return <div>Loading...</div>;

    return (
        <div>
            <h1>{data.title}</h1>
            <p>{data.body}</p>
        </div>
    );
};

export default App;

伺服器端渲染 SSR

SSR(Server-Side Rendering)是在伺服器端生成完整的 HTML 頁面,將已經處理好的頁面回傳給瀏覽器,瀏覽器僅負責頁面的互動功能。

SSR 比起 CSR,使用者能更快看到完整頁面,但由於其處理機制,也對伺服器的負擔較大。

伺服器端渲染對 SEO 極為友善,因為頁面內容已經處理好才發送給使用者,爬蟲能清楚地了解網頁內容。

SSR 的渲染步驟

  1. 訪客透過瀏覽器發出請求。
  2. 伺服器接收到該請求。
  3. 伺服器根據路由動態生成 HTML 頁面,並透過資料庫或 API 取得頁面資料。
  4. 伺服器將生成的 HTML 頁面返回給瀏覽器。
  5. 瀏覽器解析 HTML,渲染出完整畫面。
  6. 訪客看到完整的頁面

React.js 實現伺服器端渲染

my-app/
├─ pages/
│   ├─ index.js      # 伺服器端渲染的頁面

pages/index.js

import React from 'react';

const HomePage = ({ post }) => {
    return (
        <div>
            <h1>{post.title}</h1>
            <p>{post.body}</p>
        </div>
    );
};

// 伺服器端渲染函數 (Next.js 特有的)
export async function getServerSideProps() {
    const res = await fetch('https://jsonplaceholder.typicode.com/posts/1');
    const post = await res.json();

    return {
        props: { post },
    };
}

export default HomePage;

靜態網站生成 SSG

SSG(Static Site Generation)是在構建階段(Build Time)預先產生靜態 HTML 頁面,這些頁面在使用者 request 時直接提供,由於已經是處理好的 HTML,因此渲染速度極快且 SEO 友好。

SSG 渲染步驟

  1. 在構建時期 (Build Time),開發者運行構建命令,預先生成所有靜態頁面。
  2. 伺服器或 CDN 儲存這些靜態 HTML 文件。
  3. 用戶請求頁面時,伺服器直接返回預先生成的靜態 HTML。
  4. 瀏覽器渲染頁面,React 進行 Hydration 使頁面可交互。

React.js 實現靜態網站生成

my-app/
├─ pages/
│   ├─ index.js
│   ├─ blog/
│       ├─ [id].js    # 動態路由靜態生成

核心代碼 pages/blog/[id].js

import React from 'react';

const BlogPost = ({ post }) => {
    return (
        <div>
            <h1>{post.title}</h1>
            <p>{post.body}</p>
        </div>
    );
};

// 在構建時生成靜態頁面
export async function getStaticPaths() {
    const res = await fetch('https://jsonplaceholder.typicode.com/posts');
    const posts = await res.json();

    const paths = posts.map((post) => ({
        params: { id: post.id.toString() },
    }));

    return { paths, fallback: false };
}

// 提供靜態頁面資料
export async function getStaticProps({ params }) {
    const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`);
    const post = await res.json();

    return {
        props: { post },
    };
}

export default BlogPost;

增量靜態重新生成 ISR

ISR(Incremental Static Regeneration)是 SSG 的延伸應用,允許根據設定的時間間隔(revalidate),在後台自動重新生成靜態頁面,實現靜態頁面的動態更新

  • 渲染時機:構建時生成靜態頁面,根據 revalidate 時間進行再生。
  • SEO 支持:非常好。
  • 首屏加載速度:快,提供靜態 HTML。

渲染步驟

  1. 在構建時期預生成初始靜態頁面。
  2. 用戶請求時,伺服器提供靜態 HTML。
  3. 當頁面過期(超過設定的 revalidate 時間)時,伺服器在後台重新生成頁面。
  4. 下一位用戶請求時會看到更新的內容。
// pages/blog/[slug].js
import { useRouter } from 'next/router';

export default function BlogPost({ post }) {
    const router = useRouter();

    // 顯示載入狀態(可選)
    if (router.isFallback) {
        return <div>Loading...</div>;
    }

    return (
        <article>
            <h1>{post.title}</h1>
            <p>{post.content}</p>
        </article>
    );
}

// 在構建時生成頁面
export async function getStaticPaths() {
    const res = await fetch('https://api.example.com/posts');
    const posts = await res.json();

    const paths = posts.map((post) => ({
        params: { slug: post.slug },
    }));

    return { paths, fallback: 'blocking' };
}

// 提供靜態頁面生成和增量更新邏輯
export async function getStaticProps({ params }) {
    const res = await fetch(`https://api.example.com/posts/${params.slug}`);
    const post = await res.json();

    return {
        props: {
            post,
        },
        revalidate: 60, // 每 60 秒重新生成頁面
    };
}

不同的頁面渲染方式比較

特性CSRSSRSSGISR
SEO 友善非常好非常好非常好
載入畫面中等
伺服器負載最低
更新頻率即時中等
適用場景SPA、
管理系統
SEO、
動態網站
Blog、
文檔網站
電商、
新聞媒體

網站開發人員能根據以上的表格中的優缺點與應用情境,決定合適的渲染方式。React 可以使用 Next.js 提供混合渲染策略,達到最佳性能和 SEO 效果!

透過動態渲染改善 CSR 頁面

動態渲染(Dynamic Rendering)是一種針對搜尋引擎爬蟲與訪客瀏覽器提供不同內容的技術。這種方法的主要目的是改善單頁應用(SPA)或使用 CSR 網站的 SEO 表現,確保搜尋引擎能夠正確檢索和索引網站內容。

動態渲染的判斷流程

在動態渲染的架構下:

  • 如果 request 來自 Googlebot,伺服器會 response 預先渲染(Prerender)的靜態 HTML,以確保爬蟲能看到完整的頁面,以達到 SEO 友善。
  • 如果 request 來自一般瀏覽器,則正常執行 CSR,透過 JavaScript 載入並渲染頁面。

下面是常見的動態渲染解決方案,可以導入在前端框架開發的 CSR 網頁上:

  • Prerender.io:基於 Headless Chrome 的預渲染解決方案,它會在伺服器上自行透過瀏覽器將 JavaScript 渲染後的 HTML 儲存起來,然後根據請求來源提供對應的內容。
  • Rendertron:Google 提供的開源解決方案,與 Prerender.io 類似,它也會使用 Headless Chrome 預渲染 JavaScript,然後為爬蟲提供靜態 HTML。

References

Dynamic Rendering as a workaround | Google for Developers
Dynamic Rendering with Rendertron  |  Google for Developers
Rendering on the Web  |  Articles  |  web.dev
Data Fetching: Incremental Static Regeneration (ISR) | Next.js