跳至主要內容

    SSR vs CSR 偵測器使用教學

    這篇教你如何快速判斷一個網站是用 SSR(伺服器端渲染)、CSR(客戶端渲染)還是 SSG(靜態生成),以及為什麼渲染模式會影響 SEO、Core Web Vitals 與爬蟲索引。

    1) 三種渲染模式:SSR / CSR / SSG

    • SSR(Server-Side Rendering):每次請求都在伺服器端產生完整 HTML,適合動態內容與個人化需求。例如:Next.js getServerSideProps、Nuxt server routes。
    • CSR(Client-Side Rendering):伺服器只回傳空殼 HTML + JavaScript bundle,內容由瀏覽器執行 JS 後渲染。例如:傳統 Create React App、Vue CLI(無 SSR)。
    • SSG(Static Site Generation):在建置時預先產生所有 HTML,部署後直接提供靜態檔案。適合內容不常變動的頁面。例如:Next.js getStaticProps、Astro、Gatsby。
    html
    <!-- SSR/SSG 輸出:完整 HTML -->
    <body>
      <div id="root">
        <h1>Developer SEO Hub</h1>
        <p>Free SEO tools for developers.</p>
      </div>
      <script src="/app.js"></script>
    </body>
    
    <!-- CSR 輸出:空殼 HTML -->
    <body>
      <div id="root"></div>
      <script src="/app.js"></script>
      <!-- 內容要等 JS 執行後才出現 -->
    </body>

    2) 為什麼渲染模式影響 SEO?

    Google 雖然可以執行 JavaScript,但 CSR 網站會有幾個潛在問題:

    • 延遲索引:Googlebot 要等 JS 執行完才能看到內容,可能延後幾小時甚至幾天才索引。
    • LCP / FID 變差:CSR 的 First Contentful Paint 與 Largest Contentful Paint 通常較慢,影響 Core Web Vitals 分數。
    • JS 錯誤風險:如果 JS bundle 載入失敗或執行錯誤,爬蟲可能只抓到空白頁面。
    • 社群分享預覽:Facebook/Twitter 爬蟲不執行 JS,CSR 網站的 OG image/title 可能抓不到。
    javascript
    // CSR:爬蟲看到的初始 HTML 可能是空的
    // View Source 只會看到:
    <div id="root"></div>
    
    // SSR/SSG:爬蟲直接看到完整內容
    <div id="root">
      <h1>完整標題</h1>
      <p>完整內容</p>
    </div>

    3) 如何偵測網站的渲染模式與框架?

    1. 打開 SSR vs CSR 偵測器,輸入要分析的網址。
    2. 工具會檢查 HTML source、JS bundle、HTTP headers 與特徵字串(例如 __NEXT_DATA__、nuxt、hydration markers)。
    3. 結果會顯示:
      • 渲染模式(SSR / CSR / SSG / Hybrid)
      • 偵測到的框架(Next.js / Nuxt / Astro / React / Vue 等)
      • Hydration 狀態(是否有 hydration errors)
      • 建議(例如「建議改用 SSR 或 prerendering」)
    4. 若是 CSR 且 SEO 很重要,考慮:
      • 升級到 SSR 框架(例如 Next.js App Router、Nuxt 3)
      • 使用 prerendering 服務(例如 prerender.io、Cloudflare prerendering)
      • Dynamic Rendering(給爬蟲回傳 prerendered HTML,給使用者回傳 CSR)

    4) Hydration 與常見問題

    SSR/SSG 框架通常會做 hydration(把伺服器端產生的 HTML「接管」到 React/Vue 等框架)。Hydration 失敗常見原因:

    • server 與 client HTML 不一致:例如伺服器端產生 <div>A</div>,但客戶端 JS 想渲染 <div>B</div>
    • useEffect / componentDidMount 改變 DOM:在 hydration 過程中修改 DOM 結構。
    • 第三方腳本干擾:廣告、analytics 腳本在 hydration 前插入 DOM。
    javascript
    // ❌ 錯誤:server 與 client 不一致
    function MyComponent() {
      const [mounted, setMounted] = useState(false);
      useEffect(() => setMounted(true), []);
      return <div>{mounted ? 'Client' : 'Server'}</div>;
      // server HTML: <div>Server</div>
      // client 想要: <div>Client</div> → Hydration mismatch!
    }
    
    // ✅ 正確:使用 suppressHydrationWarning 或確保一致
    function MyComponent() {
      return <div suppressHydrationWarning>{new Date().toISOString()}</div>;
    }

    延伸閱讀

    常見問題

    SSR vs CSR 偵測與最佳實務。