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)、Turbopack、Biome 都是用 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,你會發現一個關鍵事實——產出裡只有你實際寫過的那三個 utility(bg-brand、text-white、p-4)對應的規則,加上基礎 reset 樣式與 @theme 定義的 CSS 變數。你沒用到的 mt-8、grid、rotate-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、@property、color-mix()、OKLCH 色彩空間),因此拉高了瀏覽器門檻:Safari 16.4+、Chrome 111+、Firefox 128+。若你的專案必須支援更舊的瀏覽器,應繼續使用 v3.4,而非硬上 v4。
v3 vs v4:架構總對比
最後用一張表把 v3 與 v4 的架構差異收攏起來:
| 面向 | v3 | v4 |
|---|---|---|
| 核心引擎 | JavaScript(Node.js) | Rust(Oxide)透過 NAPI-RS |
| 配置方式 | tailwind.config.js | CSS @theme { } 指令 |
| 內容偵測 | 手動設定 content 陣列 | 自動偵測,尊重 .gitignore |
| CSS 入口 | @tailwind base/components/utilities | @import "tailwindcss" |
| CSS 壓縮與前綴 | Autoprefixer + cssnano | 內建 Lightning CSS |
| PostCSS 依賴 | 必要 | 可選(三種整合方式之一) |
| 全量建構速度 | 基準 1x | 約 10x |
| 增量建構速度 | 基準 1x | 約 100x |
| 設計 Token | JS 物件(theme.colors) | CSS 變數(--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「憑空消失」的陷阱。