DEV Community

JH5
JH5

Posted on • Originally published at Medium

Google PageSpeed Insights 慘不忍睹的 Next.js 效能優化

Google PageSpeed Insights 慘不忍睹的 Next.js 效能優化

最近用Next.js打造了一個功能強大?的網站,但上線後放在 Google PageSpeed Insights 上一測,分數慘不忍睹… 尤其是最大內容繪製 (LCP) 時間竟然高達 15 秒?

UpdatedMarch 24, 2026•2 min read

Google PageSpeed Insights 慘不忍睹的 Next.js 效能優化

JJhihHao Wu**近期研究重點包含 AI Agent 的供應鏈攻擊、PII 偵測模型評估,以及醫療 AI 在臨床流程中的安全落地。

在這裡,我分享深度技術實測報告(如 NVIDIA NeMo, WildGuard)與職場技術成長心得,致力於在 AI 浪潮中打造具備資安韌性的解決方案。**Part of seriesAI 工具與模型評測

On this page

Google PageSpeed Insights 慘不忍睹的 Next.js 效能優化緩慢的元兇 —Client-Side Rendering擁抱 (Server-Side Rendering, SSR)Next.js App Router 中的 SSR 實作其他效能優化點

Google PageSpeed Insights 慘不忍睹的 Next.js 效能優化

最近用Next.js打造了一個功能強大?的網站,但上線後放在 Google PageSpeed Insights 上一測,分數慘不忍睹… 尤其是最大內容繪製 (LCP) 時間竟然高達 15 秒?

這一篇將紀錄與分享一次完整的效能優化實戰,紀錄前陣子如何診斷問題與作架構調整,將 LCP 從 15.1 秒的「紅色警戒」成功降至 2 秒內的「綠色健康」範圍。

PageSpeed Insights Result

緩慢的元兇 —Client-Side Rendering

初始的 PageSpeed 報告如下:

  • Largest Contentful Paint (LCP): 15.1 s

  • Total Blocking Time (TBT): 1,190 ms

問題還滿明顯的,目前的頁面採用了典型的 CSR 模式:伺服器會先回傳一個基本的 HTML 空殼,頁面上顯示著 “載入中…”,然後所有內容都交給瀏覽器的 JavaScript 來處理。

CSR 的工作流程如下:

  1. 瀏覽器下載 HTML。

  2. 瀏覽器下載、解析並執行 JavaScript 檔案。

  3. JavaScript 發出 API 請求以獲取資料。

  4. 等待資料回傳。

  5. JavaScript 根據資料渲染出完整的資料列表。

這個漫長的鏈條導致了兩個主要問題:

  • 高 LCP:直到第 5 步完成,頁面的「最大內容」(資料列表)才被繪製出來,耗時極長。

  • 高 TBT:在第 2、3、5 步中,瀏覽器主線程被大量 JavaScript 任務阻塞,導致頁面無法即時回應使用者操作。

擁抱 (Server-Side Rendering, SSR)

為了解決這個問題,後來改用 CSR 到 SSR。

SSR 的核心思想是:將原本在客戶端進行的資料獲取和內容渲染工作,轉移到伺服器端完成。

SSR 的工作流程:

  1. 瀏覽器發出頁面請求。

  2. Next.js 伺服器接收請求,並在伺服器環境下獲取資料。

  3. 伺服器使用獲取到的資料,將頁面完整渲染成 HTML 字串。

  4. 伺服器將這個包含所有內容的完整 HTML 回傳給瀏覽器。

  5. 瀏覽器接收到 HTML 後,可以直接繪製出完整頁面。

這樣一來,LCP 的時間點被大幅提前到第 5 步,因為瀏覽器不再需要等待 JavaScript 執行和 API 請求。

Next.js App Router 中的 SSR 實作

在 Next.js 的 App Router 架構下,改成SSR也是非常直覺,頁面元件預設就是伺服器元件 (Server Components)。

修改前 (CSR 模式):

// src/app/page.tsx (Before)  
'''use client'''; // 必須標記為客戶端元件
Enter fullscreen mode Exit fullscreen mode
import { useState, useEffect } from 'react';  
import JobList from '@/components/JobList';
Enter fullscreen mode Exit fullscreen mode
export default function HomePage() {  
  const [jobs, setJobs] = useState([]);  
  const [loading, setLoading] = useState(true);
Enter fullscreen mode Exit fullscreen mode
useEffect(() => {  
    async function fetchJobs() {  
      const response = await fetch('/api/jobs');  
      const data = await response.json();  
      setJobs(data);  
      setLoading(false);  
    }  
    fetchJobs();  
  }, []);
Enter fullscreen mode Exit fullscreen mode
if (loading) {  
    return <div>載入中...</div>;  
  }
Enter fullscreen mode Exit fullscreen mode
return <JobList jobs={jobs} />;  
}
Enter fullscreen mode Exit fullscreen mode

修改後 (SSR 模式):

// src/app/page.tsx (After)  
import JobList from '@/components/JobList';  
import { fetchJobsFromFirestore } from '@/lib/firebase'; // 假設這是從 Firestore 獲取資料的函數
Enter fullscreen mode Exit fullscreen mode
// 頁面變成一個 async function  
export default async function HomePage() {  
  // 1. 直接在伺服器端獲取資料  
  const initialJobs = await fetchJobsFromFirestore({ limit: 20 });
Enter fullscreen mode Exit fullscreen mode
// 2. 將資料直接傳遞給子元件  
  return <JobList initialJobs={initialJobs} />;  
}
Enter fullscreen mode Exit fullscreen mode

修改之後,先是移除了 '''use client''',讓頁面變回預設的伺服器元件,並將資料獲取的邏輯直接放在 async 的頁面元件中,而Next.js 會在伺服器上 await 這個資料請求完成,然後才把渲染好的 HTML 送出。

其他效能優化點

除了 SSR,這次也一併改了下面幾個小地方:

  1. 圖片優化 (next/image):自動處理圖片格式 (WebP)、尺寸和延遲載入。

  2. 字體優化 (next/font):避免字體檔案載入造成的版面位移 (CLS) 和文字閃爍。

  3. 動態載入 (next/dynamic):對於不在初始可視區域內的元件(例如頁尾的複雜互動元件),可以使用動態載入,減少主要 JS 檔案的大小。

  4. 預先連線 (preconnect):在 layout.tsx 中使用 <link rel="preconnect"> 提前與重要的第三方網域(如 Google Fonts, Firebase API)建立連線,減少後續請求的延遲。

改善後的頁面再次部署到Cloud Run 後,LCP 和 TBT 兩個部分已經有很大的改善了,應該也跟大部分優化實戰推薦的,從 CSR 轉向 SSR/SSG 是解決現代前端應用 LCP 和 TBT 過高問題最有效的方法之一。

透過利用 Next.js 提供的伺服器元件和資料獲取功能,可以將繁重的工作留在伺服器,換來提供給使用者一個流暢的瀏覽體驗,同時也滿足了搜尋引擎對於網站速度的要求。

其他還是偏慢的部分補功能陸續補足時,順便再花一點時間來修理,下一步應該會丟一個Github Action來在每次部署到Cloud ,利用 PageSpeed Insights API 來測測看有沒有改壞。

# nextjs# seo

Top comments (0)