Skip to content

導入 Tailwind、Victory 以及處理 Vite 建置

Yuan Chiu edited this page May 14, 2026 · 1 revision

Viewed package.json:1-30

這次重構確實涉及了多個層次的技術細節(從前端框架、建置工具到部署流程)。為了幫您消化,我將這次導入 Tailwind、Victory 以及處理 Vite 建置的核心作法總結為以下四個關鍵模塊:

1. Tailwind CSS 的編譯與整合

在不使用 CDN (unpkg) 的獨立運行架構下,Tailwind 的處理流程如下:

  • 離線編譯:透過 @tailwindcss/clisrc/core/input.css 編譯成 gen/output.css。這解決了對外連網的依賴。
  • 自定義字體:在 input.css 中使用 @font-face 定義您的 SpaceFont(指向 /font.woff2),並在 @theme 中將其設定為 sans 的預設值。
  • 資產打包:編譯出的 CSS 不直接在網頁引用,而是由 generate-assets.ts 讀取並轉換成 Base64 字串,存放在 assets.gen.ts 中,最後由 Hono 直接內嵌在 HTML 的 <style> 標籤中。

2. Victory (React) 的客戶端渲染與 Bug 修復

Victory 是一個複雜的圖表庫,在 Cloudflare Workers (SSG) 環境下的導入重點:

  • JSX Pragma (解決 Error #31): 這是最關鍵的一點。因為專案同時存在 Hono (SSR) 和 React (Client),Vite 預設可能會用 Hono 的 JSX 轉換器去處理 React 檔案。
    • 作法:在 main.tsx 最頂端加入 /* @jsxImportSource react */
    • 原理:這確保了 Vite 會使用 React 的標準格式來編譯圖表組件,避免 React 在瀏覽器中因讀不到正確的物件格式而崩潰。
  • 模組化 AJAX:建立 api.ts 統一處理 fetch 邏輯,讓 React 組件能非同步獲取資料,確保頁面初始載入(SSG)極快,而圖表則在後端資料回傳後動態渲染。

3. Vite 的資產打包流水線 (Asset Pipeline)

為了讓專案能獨立運行,我們建立了一套自動化流程:

  1. Vite Build:將 main.tsx 打包成單一的 client.js
  2. Tailwind Build:產出 output.css
  3. Asset Generator (核心)
    • 這是一個自研腳本 (scripts/generate-assets.ts)。
    • 它負責:字體子集化 (Subset font)、讀取 JS/CSS/圖片、將它們全部轉為 Base64。
    • 最後生成一個 assets.gen.ts 供伺服器端 (app.ts) 呼叫。

4. 解決無限迴圈與部署問題 (架構優化)

這是最後處理的最混亂但也最重要的部分:

  • 目錄隔離
    • 問題wrangler dev 會監聽 src 的變動。如果建置產物寫入 src/gen,會導致 監聽 -> 建置 -> 檔案變動 -> 重新監聽 的無限迴圈。
    • 作法:將產出目錄移至根目錄的 /gen(與 src 平級),並在 .gitignore 忽略它。
  • 部署腳本封裝
    • package.json 封裝 "deploy": "npm run build:assets && wrangler deploy"
    • 這樣不論是在本地手動部署,還是在 Cloudflare Dashboard 的自動化 CI 環境,都能確保「先產出資產,再執行部署」,避免發生 Could not resolve assets.gen.js 的錯誤。

總結您的「消化清單」:

  1. React 檔案:一定要記得檢查 JSX 轉換來源 (react vs hono)。
  2. 建置產物:永遠不要放在 wrangler 正在監聽的原始碼目錄內。
  3. 環境變數/依賴:改用 package.jsonscripts 來串接多個建置步驟,比寫在 wrangler.jsoncbuild 塊更穩定且易於本地除錯。

這套作法雖然初期設定較繁瑣,但它建立了一個非常強大的離線優先 (Offline-first) 架構,即便在沒有網路的情況下,只要有 Node.js 環境,您的 Dashboard 就能完整編譯與運作!


有個問題,Vite不是處理網站資源打包嗎?本身不能順便處理Tailwind編譯嗎?我看Build的工具鏈已經很複雜了,我有在想build:css 要做的事情能不能合併進Vite裡?

Viewed package.json:1-30

這是一個非常敏銳的觀察!Vite 本身確實具備極強的 CSS 處理能力,完全可以整合 Tailwind。

目前的工具鏈之所以看起來比較「分開」,是因為我們現在採用的是 Hono (伺服器端) + Vite (客戶端) 的混合架構,這導致了兩個工具在處理 CSS 時的權責稍微重疊了:

為什麼現在是分開的?

  1. Vite 的角色:目前 Vite 只負責編譯「瀏覽器跑的 JS」(即 Victory 圖表部分)。它產出的 CSS 通常會被封裝在 dist 資料夾裡,並帶有隨機雜湊檔名(例如 main-ab12.css)。
  2. Hono 的角色:伺服器渲染 (SSR/SSG) 產生的 HTML 外殼(包含導覽列、背景色等)也需要 Tailwind。如果交給 Vite 處理,我們的伺服器端程式碼會很難預測編譯後的 CSS 檔名,這會增加資產打包 (generate-assets.ts) 的複雜度。
  3. Tailwind v4 CLI 的特性:Tailwind v4 標榜「零配置」,它的 CLI 極快且獨立,對於像我們這種需要將 CSS 轉為 Base64 嵌入 Worker 記憶體的專案來說,獨立呼叫 CLI 可以確保我們得到一個路徑固定、內容純淨output.css

如果要合併進 Vite,該怎麼做?

如果您希望簡化,確實可以這樣做。方法是導入 Tailwind v4 的 Vite 插件

  1. 安裝插件npm install @tailwindcss/vite
  2. 修改 vite.config.ts
    import tailwindcss from '@tailwindcss/vite';
    export default defineConfig({
      plugins: [tailwindcss(), react()],
      // ... 
    });
  3. main.tsx 引入 CSS
    import '../input.css'; // 讓 Vite 去追蹤這份 CSS

合併後的優缺點:

  • 優點
    • package.json 的指令會少一行。
    • Vite 可以同時優化 JS 和 CSS(例如進行更深度的樹搖優化)。
  • 缺點 (在本專案中)
    • 路徑問題:Vite 編譯出的 CSS 會躲在 gen/dist/client/assets/ 底下且檔名不固定。您的 generate-assets.ts 會需要寫額外的邏輯去「撈」出這份 CSS 檔名,才能把它塞進 assets.gen.ts
    • 開發體驗:目前分開跑時,您可以單獨編譯 CSS 而不觸發 Vite 複雜的打包邏輯,這在微調樣式時速度極快。

結論與建議

目前的做法雖然看起來多了一條指令,但它實現了**「關注點分離」**:

  • Vite 專心處理複雜的 React/Victory 邏輯。
  • Tailwind CLI 專心生產全局樣式。
  • Asset Script 專心把兩者打包進 Worker。

如果您覺得指令太多太亂,我建議維持現狀但優化 package.json。其實這也是目前許多高效能專案(如 Remix 或早期 Hono 專案)偏好的做法:讓專業的工具處理專業的事

除非您的專案規模大到需要 Vite 的高級 CSS 處理功能(例如 CSS Modules 或 PostCSS 插件群),否則目前的「獨立編譯、統一打包」模式其實是最容易維護且效能最高的喔!

Clone this wiki locally