跳至主要內容
Skip to content

在最近的專案優化中,我們嘗試在 VitePress 環境中引入了最前衛的組合:Tailwind CSS v4Nuxt UI v4。雖然這兩者都帶來了極佳的開發體驗,但在 VitePress 這種強依賴伺服器端渲染 (SSR) 場景下,還是踩到了一些有趣的坑。

這篇文記錄了我們如何解決 SSR 水合 (Hydration) 錯誤,以及如何精確映射 Tailwind v4 的色階給 Nuxt UI。


一、 消失的組件:解決 SSR 水合衝突

問題現象

在使用 Nuxt UI 組件(如 <UButton>)後,我們發現生產環境 Build 出來的 HTML 標籤是空的,或者出現組件內容「閃爍」的情況(FOUC)。

原因分析

在 VitePress 的 theme/index.ts 中,我們起初為了避開 SSR 環境下的 window 存取錯誤,將 Nuxt UI 組件註冊放在了 if (!import.meta.env.SSR) 判斷中:

typescript
// ❌ 錯誤做法:只在客戶端註冊
if (!import.meta.env.SSR) {
  app.use(ui)
  app.component('UButton', UButton)
}

這會導致 VitePress 在 Node.js 端生成靜態 HTML 時,不認識自定義組件標籤,直接略過它們。

解決方案

應將 組件註冊外掛初始化 分開。組件必須在雙端都註冊,而具有副作用的外掛則保留在客戶端。

typescript
// ✅ 正確做法
app.component('UButton', UButton) // 雙端註冊

if (!import.meta.env.SSR) {
  app.use(ui) // 僅客戶端
}

二、 Tailwind v4 的動態色階映射

問題現象

Nuxt UI v4 大量依賴 CSS 變數進行主題控制。如果只定義了單一的 --ui-primary,組件在 Hover 或 Active 狀態下的顏色過渡會變得非常生硬,因為它找不到對應的 -500-600 等變數。

優化策略

style.css 中利用 Tailwind v4 的 @theme 系統,手動補完所有色階映射。這雖然看起來繁瑣,但能確保組件在所有狀態下都有完美的視覺表現:

css
:root {
  --ui-primary: var(--color-matcha-500);
  
  /* 精確映射 50-950 色階 */
  --ui-color-primary-50: var(--color-matcha-50);
  --ui-color-primary-100: var(--color-matcha-100);
  /* ... 消略中間 ... */
  --ui-color-primary-900: var(--color-matcha-900);
  --ui-color-primary-950: var(--color-matcha-950);
}

三、 強制佈局與 VitePress 的權衡

VitePress 為了閱讀體驗,預設對 .VPDoc 的內容寬度有嚴格限制(通常是 688px)。為了實現「全螢幕且具備專業感」的工程師部落格,我們使用了較強效的 CSS 覆寫。

在使用 !important 覆寫時,必須注意 --vp-content-max-width 的定義,以避免破壞 VitePress 內建的響應式側邊欄邏輯。

總結

優化項目核心動作預期效果
SSR 水合雙端註冊組件,僅客戶端初始化外掛消除初次渲染的樣式閃爍與標籤缺失
主題映射手動補完 50-950 CSS 變數確保組件在所有互動狀態下顏色一致
佈局覆寫調整 CSS 變數與 !important 權重實現全螢幕設計同時保留響應式能力

進階挑戰

  1. 嘗試將 Nuxt UI 的 primary 色系動態切換為專案中的其他顏色,並觀察 CSS 變數如何影響組件渲染。
  2. 研究 VitePress 的 transformHtml 鉤子,看是否能更優雅地處理 SSR 期間的自定義標籤。

延伸閱讀與資源

返回專題首頁