TailwindCSS 架構與 Oxide 引擎:JIT、Rust 與 CSS 處理管線完整解析 | TailwindCSS 完整教學

2026/08/02
TailwindCSS 架構與 Oxide 引擎:JIT、Rust 與 CSS 處理管線完整解析 | TailwindCSS 完整教學

TailwindCSS v4 最大的改變不在你寫的 class,而在你看不到的引擎。這篇文章帶你打開引擎蓋,看看以 Rust 重寫的 Oxide 引擎如何運作:它怎麼掃描你的原始碼、按需產生 CSS,又為什麼建構速度能比 v3 快上一個數量級。這是 TailwindCSS 完整教學 系列的第二篇,也是理解整個框架運作原理的關鍵。

前言

Oxide 是 TailwindCSS v4 的核心建構引擎——它負責把你散落在 HTML、JSX、Vue 檔案裡的 class 字串,轉換成一份只包含你實際用到的樣式的 CSS 檔。上一篇《Utility-First 哲學》我們談了「為什麼」要用一堆小型 utility class,這一篇要談的是「怎麼做到的」。

用一個現實世界的類比來理解:想像一間按單生產的工廠。傳統的 CSS 預處理器像是先把倉庫塞滿所有可能的商品,再派人去清點哪些沒賣掉、退回銷毀(這正是舊時代 Tailwind 搭配 PurgeCSS 的做法)。而 JIT(Just-In-Time,即時編譯) 引擎像是一條接單才開工的生產線——你在 HTML 裡寫下 bg-blue-500,這張「訂單」被掃描器讀到,生產線才即時打造出對應的 CSS 規則。沒下單的,一律不生產。v4 的 Oxide 引擎,就是把這條生產線從 JavaScript 換成了效能更猛的 Rust。

本篇你將學到:

  • JIT 即時編譯的核心思維,以及它如何取代舊時代的「先全量、後清除」模式
  • v4 的 Oxide 引擎(Rust)內部由哪些元件組成,CSS 處理管線如何從「掃描」走到「輸出」
  • Lightning CSS 在管線末端扮演的角色,以及它取代了哪些傳統工具
  • v3 與 v4 在架構與效能上的根本差異,以及三種安裝整合方式的實作

本系列以 TailwindCSS v4 為預設版本,遇到與 v3 有明顯差異之處會特別標註。

核心概念

從 JIT 說起:按需產生的思維

要理解 Oxide,得先理解 JIT。在 JIT 出現之前(Tailwind v1 與早期 v2),Tailwind 的運作方式是:先產生一個包含所有可能 utility 組合的巨大 CSS 檔(未壓縮動輒數 MB),開發時直接載入,正式上線前再靠 PurgeCSS 掃描一次,把沒用到的規則刪掉。

這個模式有幾個痛點:開發環境的 CSS 檔肥大、修改設定要重新產生整個檔案、任意值(如 top-[117px])無法支援,因為根本不可能窮舉所有數值。

JIT 反轉了這個流程:不再「先全量、後清除」,而是「掃描你用到什麼,就只產生什麼」。它在 v2.1 以外掛形式登場、v3 成為預設引擎,而 v4 則把整套 JIT 邏輯以 Rust 原生實作進 Oxide 引擎。

舊模式(v1 / 早期 v2):先全量、後清除
═══════════════════════════════════════════════════════
產生所有可能的 utility(數 MB)→ 開發載入巨大檔案
                                → 上線前用 PurgeCSS 刪掉沒用到的

JIT 模式(v3 預設 / v4 由 Oxide 原生):按需產生
═══════════════════════════════════════════════════════
掃描原始碼 → 只找出你實際用到的 class → 只產生這些規則
(產出天生就是最小集合,不需要事後清除步驟)

JIT 帶來三個直接好處:產出 CSS 天生就小(只含用到的規則)、任意值成為可能w-[137px] 在掃描到當下才即時生成規則)、以及開發即時(改一個 class 只需重新產生那一小塊)。

Oxide 引擎:為什麼是 Rust?

v3 的 JIT 引擎是純 JavaScript 實作,在中小型專案上運作良好,但在大型 mono-repo 中,掃描速度會顯著下滑。v4 的答案是把引擎以 Rust 重寫,這就是 Oxide

為什麼是 Rust?核心動機在於 JavaScript 的幾個先天限制:

JavaScript 效能瓶頸 vs Rust 的優勢
═══════════════════════════════════════════════════════

JS 的瓶頸:
  ├── V8 JIT 熱身時間:每次啟動都要重新 JIT 編譯
  ├── GC(垃圾回收)停頓:影響增量建構的一致性
  ├── 單執行緒限制:Worker Threads 有通訊開銷
  └── 正則引擎效能不如 Rust 的 regex crate

Rust 的優勢:
  ├── 零成本抽象:高層語法不影響執行效能
  ├── 並行安全:資料並行無 race condition 疑慮
  ├── 無 GC 停頓:確定性記憶體管理
  └── 啟動即達峰值速度,無 JIT 熱身

一個容易誤解的重點:Oxide 不是 WASM,而是透過 NAPI-RS 這個橋接層直接編譯成原生二進位,掛載進 Node.js。

Node.js  ←→  NAPI-RS  ←→  Rust Binary(原生機器碼)
                              ↑
              原生速度,且無 WASM 的記憶體複製開銷

這其實是整個前端工具鏈的大趨勢——SWC(取代 Babel)、TurbopackBiome 都是用 Rust 重寫熱路徑來換取數量級的效能。Tailwind v4 的 Oxide 只是加入了這個行列。

CSS 處理管線:從掃描到輸出

Oxide 引擎內部是一條清楚的管線,資料從你的原始碼流入,最後以壓縮好的 CSS 流出。整條管線可以拆成五個階段:

TailwindCSS v4 建構管線
══════════════════════════════════════════════════════════

  ┌──────────────────────────────────────────────────┐
  │  ① 設計 Token 層                                   │
  │     CSS 入口檔的 @theme { ... }                    │
  │     → 定義 --color-*、--spacing-* 等 CSS 變數      │
  └───────────────────────┬──────────────────────────┘
                          │
  ┌──────────────┐        ▼
  │ 原始碼檔案    │   ┌─────────────────────┐
  │  *.html      │──▶│ ② Scanner(掃描器)  │
  │  *.jsx/.tsx  │   │   Oxide / Rust       │
  │  *.vue       │   │   自動掃描非二進位    │
  │  *.svelte    │   │   文字檔,尊重        │
  │  *.py 等     │   │   .gitignore         │
  └──────────────┘   └──────────┬──────────┘
                                │
                                ▼
                    ┌─────────────────────────┐
                    │ ③ Parser(解析器)        │
                    │   提取 class 字串         │
                    │   解析修飾詞 sm: hover:   │
                    │   解析任意值 w-[137px]    │
                    └──────────┬──────────────┘
                                │
                                ▼
                    ┌─────────────────────────┐
                    │ ④ Generator(產生器)     │
                    │   查找 utility 定義       │
                    │   結合 @theme Token 計算  │
                    │   產生對應 CSS 規則       │
                    └──────────┬──────────────┘
                                │
                                ▼
                    ┌─────────────────────────┐
                    │ ⑤ Lightning CSS          │
                    │   加 vendor 前綴          │
                    │   CSS 語法降級            │
                    │   壓縮(minify)          │
                    └──────────┬──────────────┘
                                │
                                ▼
                    ┌─────────────────────────┐
                    │    CSS Output            │
                    │  只含實際用到的 utility   │
                    │  + 自訂的 @theme Token   │
                    └─────────────────────────┘

逐段說明這條管線做了什麼:

  • ① 設計 Token 層:v4 的最大範式轉移是「配置移進 CSS」。你在入口 CSS 的 @theme { } 區塊定義色彩、間距等設計常數,它們會變成 CSS 變數(如 --color-brand),供整條管線引用。這取代了 v3 的 tailwind.config.js
  • ② Scanner(掃描器):Oxide 自動偵測專案根目錄,掃描所有非二進位的文字型檔案,並尊重 .gitignore 規則,因此不需要像 v3 那樣手動設定 content 陣列。
  • ③ Parser(解析器):從掃描結果中提取以空格分隔的 class 字串,並解析響應式前綴(sm:md:)、狀態修飾詞(hover:dark:)、任意值(bg-[#ff0000])與堆疊修飾詞(dark:hover:)。
  • ④ Generator(產生器):查找每個 class 對應的 utility 定義,結合 @theme 的 CSS 變數計算出最終值,產生 CSS 規則,並處理負值(-mt-4)與不透明度修飾詞(bg-blue-500/50)。
  • ⑤ Lightning CSS:管線末端的後處理器,下一節詳談。

關鍵術語:Lightning CSS 的角色

Lightning CSS(由 Parcel 作者 Devon Govett 開發,同樣以 Rust 撰寫)是 v4 內建的 CSS 後處理器。它在管線末端接手 Generator 產出的原始 CSS,做三件傳統上需要多個工具才能完成的事:

Lightning CSS 在 v4 中取代的傳統工具
══════════════════════════════════════════════════════════

Vendor Prefixing(取代 Autoprefixer):
  自動補上 -webkit-、-moz- 等瀏覽器前綴

CSS 語法降級(取代 postcss-preset-env):
  input:  color: oklch(0.6 0.24 260)
  output: color: #3b82f6                     ← 舊瀏覽器 fallback
          color: oklch(0.6 0.24 260)         ← 現代瀏覽器(@supports)

CSS 壓縮(取代 cssnano):
  移除空白、合併選擇器、最佳化屬性值——且因為是 Rust,比 cssnano 更快

換句話說,v4 之前你可能需要 autoprefixer + postcss-preset-env + cssnano 三個 PostCSS 外掛才能做完的事,v4 靠一個內建的 Lightning CSS 全包了。這也是為什麼 v4 中 PostCSS 從必要依賴降級為可選整合方式之一。

實作範例

理論看完,我們來實際安裝 v4,觀察引擎產出的 CSS。v4 提供三種整合方式,依你的專案類型擇一即可。

方式一:Vite 整合(Vite 專案推薦)

如果你用 Vite(React、Vue、Svelte 專案常見),這是最順的路徑:

# 安裝核心與 Vite 外掛
npm install tailwindcss @tailwindcss/vite
// vite.config.js
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    tailwindcss(),   // 掛上 Tailwind v4 的 Vite 外掛
  ],
})
/* src/index.css —— v4 的 CSS 入口只要一行 */
@import "tailwindcss";

注意這個入口 CSS 極為簡潔,只要一行 @import "tailwindcss"

方式二:PostCSS 整合(Webpack、Next.js 等)

若你的建構工具是 Webpack 生態(例如 Next.js),走 PostCSS 整合:

npm install tailwindcss @tailwindcss/postcss
// postcss.config.js
module.exports = {
  plugins: {
    '@tailwindcss/postcss': {},   // 注意外掛名稱是 @tailwindcss/postcss
  },
}

入口 CSS 一樣是 @import "tailwindcss";

方式三:CLI(零建構工具依賴)

如果你只想要一個獨立 CLI、不想引入任何打包工具,用 @tailwindcss/cli 最直接。這也是觀察引擎產出最方便的方式:

# 安裝獨立 CLI
npm install @tailwindcss/cli

先準備一個入口 CSS 與一個 HTML:

/* src/input.css */
@import "tailwindcss";

/* 順手加一個自訂設計 Token,觀察它如何進入產出 */
@theme {
  --color-brand: oklch(0.6 0.24 260);
}
<!-- index.html —— 只用了三個 utility -->
<div class="bg-brand text-white p-4">Hello Oxide</div>

執行建構,並用 time 觀察建構耗時:

# 建構一次
npx @tailwindcss/cli -i ./src/input.css -o ./dist/output.css

# 開發時用監聽模式,改檔即時重建
npx @tailwindcss/cli -i ./src/input.css -o ./dist/output.css --watch

# 觀察建構時間(Oxide 的速度感受)
time npx @tailwindcss/cli -i ./src/input.css -o ./dist/output.css

觀察產出:只包含你用到的 utility

打開 dist/output.css,你會發現一個關鍵事實——產出裡只有你實際寫過的那三個 utilitybg-brandtext-whitep-4)對應的規則,加上基礎 reset 樣式與 @theme 定義的 CSS 變數。你沒用到的 mt-8gridrotate-45 全都不存在。

# 確認基礎 reset 樣式有被輸出
grep "*, ::before" dist/output.css

# 確認版本是 v4
npx tailwindcss --version
# 預期輸出:v4.x.x

這就是 JIT + Oxide 的核心價值具象化:你的 CSS 大小取決於你用到的 utility 種類,而不是框架有多少功能。

常見錯誤與最佳實踐

從 v3 遷移或初上手 v4 時,以下是最容易踩的幾個坑:

坑一:混用 v3 與 v4 的入口語法。 v3 的入口是三行 @tailwind 指令,v4 已改為單行 @import。這是最常見的錯誤:

/* ❌ v3 寫法(v4 不再使用,會失效) */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* ✅ v4 寫法 */
@import "tailwindcss";

坑二:仍在設定 content 陣列。 v4 的 Oxide 會自動偵測內容並尊重 .gitignore不需要手動設定掃描範圍。若你從 v3 專案帶來舊的 tailwind.config.js 並保留其中的 content 設定,可能造成非預期行為。

坑三:PostCSS 外掛名稱搞錯。 v4 的 PostCSS 外掛叫 @tailwindcss/postcss不是 v3 時代直接寫 tailwindcss。若你在 postcss.config.js 寫成 tailwindcss: {} 會無法運作。

坑四:期望所有 v3 社群外掛立即相容。 v4 的外掛 API 有所調整(新增了 @plugin 指令的 CSS-first 用法),部分 v3 社群外掛需要更新才能相容,遷移前值得先確認你依賴的外掛是否已支援 v4。

最佳實踐:保持入口 CSS 最小化。 v4 的哲學是「配置即 CSS」,理想的入口檔應該非常精簡——一行 @import,加上必要的 @theme Token,如有自訂元件才用 @layer components

/* ✅ 理想的 v4 入口:精簡、清楚 */
@import "tailwindcss";

@theme {
  --color-brand: oklch(0.6 0.24 260);
  --spacing-18: 4.5rem;
}

留意瀏覽器需求。 v4 的引擎直接依賴一批現代原生 CSS 特性(Cascade Layers、@propertycolor-mix()、OKLCH 色彩空間),因此拉高了瀏覽器門檻:Safari 16.4+、Chrome 111+、Firefox 128+。若你的專案必須支援更舊的瀏覽器,應繼續使用 v3.4,而非硬上 v4。

v3 vs v4:架構總對比

最後用一張表把 v3 與 v4 的架構差異收攏起來:

面向v3v4
核心引擎JavaScript(Node.js)Rust(Oxide)透過 NAPI-RS
配置方式tailwind.config.jsCSS @theme { } 指令
內容偵測手動設定 content 陣列自動偵測,尊重 .gitignore
CSS 入口@tailwind base/components/utilities@import "tailwindcss"
CSS 壓縮與前綴Autoprefixer + cssnano內建 Lightning CSS
PostCSS 依賴必要可選(三種整合方式之一)
全量建構速度基準 1x約 10x
增量建構速度基準 1x約 100x
設計 TokenJS 物件(theme.colorsCSS 變數(--color-*

那 10 倍與 100 倍是怎麼來的?官方基準顯示,一個典型專案的全量建構從 v3 的約 3500ms 降到 v4 的約 350ms(約 10 倍),而增量建構——也就是你改一個 class 後的重建——從約 200ms 降到約 2ms(約 100 倍)。增量建構的巨大差距,正是 Rust 無 GC 停頓、啟動即達峰值速度的直接體現,也是你在開發時「改完即見」流暢感的來源。

小結

這一篇我們打開了 TailwindCSS 的引擎蓋,回顧幾個重點:

  • JIT(即時編譯) 反轉了舊時代「先全量、後清除」的模式,改為「掃描你用到什麼,就只產生什麼」,讓產出天生最小、任意值成為可能。
  • Oxide 是 v4 以 Rust 重寫的核心引擎,透過 NAPI-RS(非 WASM)以原生速度執行,帶來約 10 倍全量、100 倍增量的建構效能。
  • CSS 處理管線走過五個階段:設計 Token → 掃描 → 解析 → 產生 → Lightning CSS 後處理,最終輸出只含你用到的 utility。
  • Lightning CSS 在管線末端一手包辦 vendor 前綴、CSS 語法降級與壓縮,取代了 Autoprefixer、postcss-preset-env、cssnano 三個傳統工具,也讓 PostCSS 從必要降為可選。
  • v4 拉高了瀏覽器門檻(Safari 16.4+、Chrome 111+、Firefox 128+),需支援舊瀏覽器的專案應留在 v3.4。

上一篇《Utility-First 哲學》我們理解了 Tailwind「為什麼」用小型 utility class,這一篇則看懂了它「怎麼」把這些 class 高效變成 CSS。你可能已經注意到,整條管線的第一步——Scanner 如何從你的原始碼裡準確找出 class 字串——其實藏著不少學問:它為什麼能認得 hover:bg-blue-500,卻可能漏掉動態拼接的 class?下一篇 《TailwindCSS 類別偵測機制》,我們就來深入這個「掃描器到底怎麼看你的程式碼」的關鍵細節,並教你如何避開讓 class「憑空消失」的陷阱。

BenZ Software Developer

熱愛技術的軟體開發者,在這裡分享程式開發經驗與學習筆記。

本週主打

AI 自動化入門包

你每天手動在做的那些煩事,其實 AI 可以自己跑。這份給你 10 個照著做就會的自動化工作流 + 50 個複製即用的提示詞,不用會寫程式。

看看這個產品 →