Skip to main content

為什麼網站要做成 SPA? SSR 的優點是什麼?

1. 為什麼網站要做成 SPA?

單頁應用程式(SPA)是指網頁在載入後,透過 JavaScript 動態更新內容,而不需要每次使用者操作都重新載入整個頁面。以下是選擇 SPA 的原因與優點,搭配詳細說明:

  1. 流暢的使用者體驗

    • 原因:SPA 在瀏覽器端處理頁面渲染,當使用者點擊連結或進行操作時,只會透過 AJAX 或 Fetch 向後端請求必要的資料,然後動態更新頁面部分內容,不需要重新載入整個頁面。

    • 好處:這種方式讓頁面切換非常快速,感覺像是在使用原生應用程式。例如,像是 Gmail 或 Trello 這樣的應用程式,點擊不同選項時,頁面內容會即時更新,沒有明顯的載入延遲。

    • 對前端工程師的意義:你可以使用像 React、Vue.js 或 Angular 這樣的框架來管理頁面狀態和 DOM 更新,讓使用者體驗更順暢。

  2. 減少伺服器負擔

    • 原因:SPA 將大部分的渲染邏輯和資料處理移到瀏覽器端,伺服器只需要提供 API 回傳 JSON 資料,而不是完整的 HTML。

    • 好處:伺服器只需要處理資料請求,負載較輕,可以支援更多同時上線的使用者。對前端工程師來說,這意味著你需要專注於撰寫 JavaScript 來處理資料並更新畫面。

    • 範例:假設你正在開發一個任務管理網站,使用者新增任務時,JavaScript 會發送 POST 請求到後端 API,然後動態將新任務加到頁面上的任務清單,不需要重新載入頁面。

  3. 模組化與可維護性

    • 原因:SPA 通常搭配現代前端框架(如 React 或 Vue.js),這些框架鼓勵元件化的開發方式,讓程式碼更容易組織和維護。

    • 好處:你可以把頁面拆分成多個可重用的元件(components),像是導覽列、表單、或卡片列表,方便團隊協作和未來擴充。

    • 對前端工程師的意義:你需要學習如何使用這些前端框架,並熟悉狀態管理(例如 Redux 或 Vuex),以確保應用程式的資料流清晰且可預測。

  4. 支援離線功能

    • 原因:SPA 可以結合 Service Worker 和快取技術,讓網站在離線狀態下也能部分運作。

    • 好處:例如,像是 Progressive Web App(PWA)可以讓使用者在沒有網路時仍能瀏覽部分內容,提升使用體驗。

    • 對前端工程師的意義:你可能需要學習如何設定 Service Worker,並在程式碼中處理快取邏輯。

SPA 的缺點

雖然 SPA 有很多優點,但也有一些挑戰,特別是對程式語言能力不強的前端工程師來說:

  • SEO 問題:因為 SPA 的內容主要由 JavaScript 動態生成,搜尋引擎可能無法有效抓取頁面內容(雖然現代搜尋引擎對 JavaScript 的支援有所改善)。

  • 首次載入時間較長:SPA 需要在瀏覽器載入所有 JavaScript 檔案,可能導致首次進入頁面時的載入時間較長。

  • 學習曲線:如果你對 JavaScript 不熟悉,學習 React 或 Vue.js 等框架可能需要花費一些時間。


2. SSR 的優點是什麼?

伺服器端渲染(Server-Side Rendering, SSR)是指網頁的 HTML 內容由伺服器預先渲染好,然後傳送到瀏覽器,讓使用者可以立即看到完整的頁面。以下是 SSR 的主要優點,並搭配詳細說明:

  1. 更好的 SEO 效果

    • 原因:SSR 會在伺服器端生成完整的 HTML 內容,搜尋引擎爬蟲可以直接讀取頁面內容,而不需要依賴 JavaScript 執行。

    • 好處:對於需要高曝光度的網站(例如電子商務網站或部落格),SSR 能確保搜尋引擎正確索引頁面內容,提升搜尋排名。

    • 對前端工程師的意義:你可能需要與後端工程師合作,確保伺服器端渲染的 HTML 結構與前端設計一致,並學習如何在框架(如 Next.js)中設定 SSR。

  2. 更快的首次載入速度

    • 原因:SSR 將渲染工作放在伺服器端,瀏覽器收到的是已經渲染好的 HTML,無需等待 JavaScript 執行。

    • 好處:使用者可以更快看到頁面內容,特別適合行動裝置或網路環境較差的情況。例如,當你造訪一個新聞網站,SSR 可以讓文章內容幾乎立即顯示。

    • 對前端工程師的意義:你需要確保前端程式碼與伺服器端渲染的內容一致,避免「閃爍」(hydration 問題,即前端重新渲染導致畫面短暫不一致)。

  3. 更好的初始使用者體驗

    • 原因:因為 SSR 直接提供完整的 HTML,使用者不需要等待 JavaScript 載入和執行,就能看到頁面。

    • 好處:這對於內容導向的網站(如部落格或新聞網站)特別重要,因為使用者可以立即開始閱讀。

    • 對前端工程師的意義:你可能需要使用像 Next.js 或 Nuxt.js 這樣的框架,學習如何設定伺服器端渲染的路由和資料取得。

  4. 相容性更好

    • 原因:SSR 不依賴瀏覽器的 JavaScript 執行能力,因此在舊版瀏覽器或禁用 JavaScript 的環境下也能正常顯示。

    • 好處:這讓網站能觸及更廣泛的受眾,特別是某些企業或政府網站需要支援舊版瀏覽器。

    • 對前端工程師的意義:你需要確保頁面在禁用 JavaScript 的情況下仍可正常運作,這可能需要額外撰寫後備(fallback)邏輯。

SSR 的缺點

  • 伺服器負擔較重:因為伺服器需要為每個請求渲染 HTML,當流量很大時可能會增加伺服器負載。

  • 開發複雜度:SSR 需要前端和後端密切配合,設定起來比純 SPA 複雜,尤其是在處理資料取得(data fetching)和狀態管理時。

  • 頁面切換較慢:與 SPA 相比,SSR 的頁面切換可能需要重新向伺服器請求,導致較慢的切換速度。


3. Universal JS 的解決方案是什麼?它的優點與實現方式

Universal JavaScript(簡稱 Universal JS,或稱 Isomorphic JavaScript)是一種混合方案,它結合了 SSR 和 SPA 的優點:在伺服器端先渲染初始頁面(像 SSR 一樣),然後在瀏覽器端接管渲染邏輯,讓後續操作變成 SPA 模式。這種方式讓程式碼可以在伺服器和客戶端「同構」(isomorphic)執行,使用相同的 JavaScript 程式碼。

為什麼要用 Universal JS?

  • 原因:純 SPA 有 SEO 和首次載入的問題,純 SSR 則頁面切換慢。Universal JS 解決這些痛點,讓網站既有好的初始載入和 SEO,又有流暢的互動體驗。

  • 常用框架:Next.js(基於 React)或 Nuxt.js(基於 Vue.js)是實現 Universal JS 的熱門工具。它們自動處理伺服器渲染和客戶端 hydration(讓前端 JavaScript 接管伺服器渲染的內容)。

Universal JS 的優點

  1. 結合 SSR 和 SPA 的好處

    • 原因:初始頁面由伺服器渲染,提供快速載入和 SEO;之後的互動由客戶端處理,提供流暢切換。

    • 好處:適合大多數現代網站,例如電子商務或內容平台,能平衡效能和體驗。

    • 對前端工程師的意義:你可以用同一套程式碼寫伺服器和客戶端邏輯,減少重複工作。

  2. 更好的效能優化

    • 原因:框架如 Next.js 支援靜態生成(SSG)和動態 SSR,讓你根據頁面需求選擇渲染方式。

    • 好處:靜態頁面可以預先建置,載入更快;動態頁面則即時渲染。

    • 對前端工程師的意義:你需要學習框架的資料取得方法,如 getServerSideProps 或 getStaticProps。

  3. 易於開發和部署

    • 原因:框架提供內建的路由、API 整合和自動優化。

    • 好處:開發速度快,部署到 Vercel 或 Heroku 等平台也很簡單。

    • 對前端工程師的意義:如果你不擅長後端,這是入門的好方式,因為框架處理了很多伺服器細節。

Universal JS 的缺點

  • 學習曲線較陡:需要了解伺服器和客戶端的差異,以及 hydration 機制。

  • 伺服器需求:需要 Node.js 伺服器來運行 JavaScript。

  • 潛在問題:如果 hydration 不當,可能導致畫面閃爍或狀態不一致。

如何實現 Universal JS?詳細教學步驟

以下用 Next.js 作為範例,因為它是基於 React 的,適合前端工程師上手。步驟詳細,讓你能跟著操作。

步驟 1: 安裝 Next.js

  • 開啟終端機(Command Prompt 或 Terminal)。

  • 建立新專案:輸入 npx create-next-app@latest my-universal-app (my-universal-app 是專案名稱,你可以改)。

  • 回答提示:選擇預設設定(No TypeScript、No ESLint 等,如果你不熟,就選 No)。

  • 進入專案資料夾:cd my-universal-app。

  • 啟動開發伺服器:npm run dev。瀏覽器打開 <http://localhost:3000> 看預設頁面。

步驟 2: 理解 Next.js 的渲染方式

  • Next.js 預設是 Universal JS:頁面在伺服器渲染,然後客戶端接管。

  • 在 /pages 資料夾下建立頁面檔案(如 index.js),它會自動變成路由。

步驟 3: 撰寫程式碼

  • 見下面的程式碼範例。

步驟 4: 測試

  • 保存檔案後,瀏覽器會自動重載。

  • 檢查網路面板(F12 > Network):初始載入是 HTML(SSR),後續互動是 JavaScript。

步驟 5: 部署(選修)

  • 用 npm run build 建置。

  • 部署到 Vercel:註冊 Vercel 帳號,輸入 vercel 指令跟著步驟。


SPA、SSR 與 Universal JS 的比較與選擇時機

為了讓你更容易理解,以下是一個簡單的比較表格:

特性SPASSRUniversal JS
首次載入速度較慢(需載入 JavaScript)較快(伺服器提供完整 HTML)較快(初始 SSR,之後 SPA)
頁面切換速度快速(前端動態更新)較慢(需重新請求伺服器)快速(客戶端接管後如 SPA)
SEO 效果較差(需額外優化)較好(直接提供 HTML)較好(初始 SSR 支援)
伺服器負擔較輕(僅提供 API)較重(需渲染 HTML)中等(初始渲染,之後客戶端)
開發複雜度較簡單(前端主導)較複雜(需前後端配合)中等(框架自動處理)
適合場景互動性強的應用程式(如 Gmail)內容導向的網站(如新聞、部落格)多數現代網站(如電商、內容平台)

選擇時機

  • SPA:高度互動的應用程式,如線上工具或後台系統。

  • SSR:純內容網站,需要高 SEO 和快速初始載入。

  • Universal JS:大多數情況的最佳選擇,平衡效能和體驗,如 Next.js 適合你從 SPA 轉移。


程式碼範例:SPA vs SSR vs Universal JS 的簡單實現

以下提供三個範例,都顯示用戶清單,資料從 API 取得。程式碼完整,不省略。

SPA(使用 React)

建立專案:npx create-react-app my-spa-app,進入資料夾 cd my-spa-app,修改 src/App.js。

// src/App.js
import React, { useState, useEffect } from 'react';

function App() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
// 模擬從 API 取得資料
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(data => {
setUsers(data);
setLoading(false);
})
.catch(error => {
console.error('錯誤:', error);
setLoading(false);
title: 為什麼網站要做成 SPASSR 的優點是什麼?
description: 比較 SPASSR、Universal JS 的原理、優缺點與選擇時機,並說明現代前端框架如何提升效能與 SEO
keywords: [SPA, SSR, Universal JS, 前端框架, React, Vue, Next.js, Nuxt.js, SEO, 伺服器端渲染, 單頁應用, 網站效能]
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)}
</div>
);
}

export default App;

說明:資料在瀏覽器端取得,使用者先看到「載入中...」。

SSR(使用 Next.js 的純 SSR 模式)

在 Next.js 專案的 pages/index.js。

// pages/index.js
import React from "react";

export async function getServerSideProps() {
// 在伺服器端取得資料
const response = await fetch("https://jsonplaceholder.typicode.com/users");
const users = await response.json();

return {
props: {
users, // 將資料傳給頁面元件
},
};
}

export default function Home({ users }) {
return (
<div>
<h1>用戶清單</h1>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}

說明:資料在伺服器端取得,直接渲染 HTML。

Universal JS(使用 Next.js)

這是 Universal JS 的範例:初始 SSR,之後客戶端可互動。修改 Next.js 的 pages/index.js,新增一個按鈕來模擬客戶端互動。

// pages/index.js
import React, { useState } from "react";

export async function getServerSideProps() {
// 伺服器端取得初始資料
const response = await fetch("https://jsonplaceholder.typicode.com/users");
const users = await response.json();

return {
props: {
initialUsers: users, // 傳給客戶端
},
};
}

export default function Home({ initialUsers }) {
const [users, setUsers] = useState(initialUsers); // 客戶端狀態
const [newUser, setNewUser] = useState("");

const addUser = () => {
if (newUser) {
setUsers([...users, { id: users.length + 1, name: newUser }]); // 客戶端動態新增
setNewUser("");
}
};

return (
<div>
<h1>用戶清單 (Universal JS)</h1>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
<input
type="text"
value={newUser}
onChange={(e) => setNewUser(e.target.value)}
placeholder="新增用戶名稱"
/>
<button onClick={addUser}>新增用戶</button>
</div>
);
}

說明

  • 初始用戶清單由伺服器渲染(SSR)。

  • 新增用戶功能在客戶端執行(如 SPA),無需重新載入頁面。

  • hydration 自動發生:客戶端 JavaScript 接管狀態。


總結與建議

  • SPA:適合純互動應用,學習 React 起步。

  • SSR:適合內容網站,注重 SEO。

  • Universal JS:推薦大多數專案,使用 Next.js 結合兩者優點。