建置工具整合:Vite、PostCSS 與 CLI 三途徑 | TailwindCSS 完整教學
建置工具整合 是把 TailwindCSS 從「範例裡的 class」變成「真實專案裡的樣式」的關鍵一步。在 v4,你有三條路:跟 Vite 深度整合的
@tailwindcss/vite(最推薦)、通用於 Next.js 等框架的@tailwindcss/postcss,以及無框架場景的@tailwindcss/cli。這一篇帶你認識背後的 Oxide 引擎與 Lightning CSS,搞懂@import "tailwindcss"與@source,並把三種建置工具的設定一次對照清楚。
前言
建置工具整合(Build Tool Integration) 講的是:你寫的那些 bg-cyan-600、flex、gap-3,到底是「誰」、在「什麼時候」把它們變成瀏覽器看得懂的 CSS 檔案。這個「誰」就是建置工具——Vite、PostCSS 或 Tailwind CLI;這個「什麼時候」就是建置流程——你存檔的瞬間、跑 npm run build 的時候。前面三十六篇我們一直在學「怎麼寫 class」,這一篇開始,我們把目光拉到「怎麼把 Tailwind 接進真實專案」。
先用一個生活化的類比。Tailwind 的建置整合,就像把一台淨水器接上你家的水管。淨水器本體(Tailwind 引擎)都一樣,差別在於「接法」:如果你家管線是新式的標準介面(Vite),有現成的專用接頭(@tailwindcss/vite),鎖上去就通,水壓還最穩;如果你家是舊式或特殊管線(Next.js 的 Webpack/Turbopack),得用一個轉接座(@tailwindcss/postcss)才能接;如果你家根本沒有固定管線,只是臨時要一桶乾淨水(靜態 HTML),那就用手動的桶裝過濾(@tailwindcss/cli),自己倒進去、過濾出來。淨出來的水(CSS)是一樣的,但接法決定了你裝起來順不順、日常用起來爽不爽。
本系列以 TailwindCSS v4 為預設版本。本篇你將學到:
- 三種安裝途徑:
@tailwindcss/vite(推薦)、@tailwindcss/postcss(通用)、@tailwindcss/cli(無框架),以及各自的適用場景 - 引擎與核心:v4 的 Oxide 引擎(Rust 實作)與 Lightning CSS 分別扮演什麼角色,為何 v4 建置快這麼多
- CSS 入口設定:
@import "tailwindcss"取代 v3 三行@tailwind指令,以及@source如何微調內容掃描 - 設定對照:Vite、PostCSS、CLI 三種建置工具的實際設定檔與指令,並標註 v3 差異
本系列以 TailwindCSS v4 為預設版本,範例皆以 v4 語法示範。凡涉及 v3 差異之處,我會特別標註。
核心概念
三種安裝途徑:先看你的專案跑在什麼上面
v4 提供三條官方整合路徑,選擇的第一原則不是「哪個最好」,而是你的專案本來就跑在什麼建置工具上。把這張表看懂,你就不會選錯:
| 途徑 | 安裝套件 | 適用場景 | 設定檔 | HMR 速度 |
|---|---|---|---|---|
| Vite Plugin | @tailwindcss/vite | Vite 專案(React/Vue/Svelte/Astro) | vite.config.ts | 最快(< 10ms) |
| PostCSS Plugin | @tailwindcss/postcss | Next.js、Webpack、通用框架 | postcss.config.mjs | 快(依框架 HMR) |
| Tailwind CLI | @tailwindcss/cli | 靜態 HTML、後端模板、原型 | 無(指令參數) | 中(--watch polling) |
判斷邏輯其實很簡單。專案在 Vite 上跑嗎? 是的話用 @tailwindcss/vite——這是官方最推薦的路徑,因為它直接掛進 Vite 的模組系統,精準知道哪個檔案被改了、只重建變動的部分,樣式更新靠 Vite 原生 HMR 毫秒級注入瀏覽器,而且不需要 postcss.config、不需要 content globs,設定最少。框架不走 Vite,而是 Webpack 或 Turbopack? 最典型的就是 Next.js App Router——那用 @tailwindcss/postcss,在 postcss.config.mjs 裡掛一個 plugin。根本沒有 JS 建置流程? 純靜態網站、PHP/Rails 後端模板、CodePen 級的原型,用 @tailwindcss/cli,一行指令搞定輸入輸出。
要強調的是:三者產出的 CSS 是等價的。選 CLI 不會比選 Vite「少功能」,@theme、@source、任意值、所有工具類別全都在。差別只在整合的緊密度與開發體驗。所以別糾結,順著你的專案走就對了。
Oxide 引擎與 Lightning CSS:v4 為什麼快
v4 之所以能把設定簡化到這種程度、又同時變快,核心是換了引擎。理解這兩個名詞,你才懂 v4 的很多「魔法」從何而來。
Oxide 是 v4 用 Rust 重寫的全新引擎,取代 v3 的純 Node.js 實作。它做三件關鍵的事:第一,自動內容偵測——用多執行緒平行掃描你專案裡的 .html、.jsx、.vue、.svelte 等原始檔找出用到的 class,並自動尊重 .gitignore(略過 node_modules、建置產物),所以你不用再手動維護 v3 那種 content 陣列。第二,增量建置快取——它記住每個檔案用了哪些 class,只有當 class 使用真的變化時才重新生成 CSS,無新 class 的重建可以快到微秒級。第三,把 CSS 的解析與 @theme、@layer 等 v4 語法原生處理掉。
Lightning CSS 則是整合進來的另一塊,負責 CSS 的「後段處理」:它取代了 v3 需要手動安裝的 autoprefixer(自動補 vendor prefix)和 cssnano(壓縮),還內建處理 @import 打包、CSS 巢狀(nesting)、現代 CSS 特性降級。這就是為什麼 v4 專案的相依套件變少了——多數情況你不再需要 autoprefixer 與 postcss-import,它們的工作 Lightning CSS 都包了。
用一句話串起來:Oxide 負責「找出並生成該有的樣式」,Lightning CSS 負責「把樣式打包、加前綴、壓縮到最佳」。兩者都是原生實作,合起來讓 v4 首次建置比 v3 快數倍、增量重建快可達百倍,這正是 Vite plugin 能做到 < 10ms HMR 的底層原因。
為什麼「快」對建置整合這麼重要?因為建置速度直接決定你的開發回饋迴圈。v3 時代改一個 class,可能要等上幾十甚至上百毫秒才看到畫面更新,累積一整天下來就是可觀的等待與分心;v4 的增量重建在沒有新 class 時能壓到微秒等級,你幾乎感覺不到延遲,存檔即所見。這也解釋了為什麼三種途徑裡 @tailwindcss/vite 最受推薦——它把 Oxide 的增量能力,直接接上 Vite「精確知道哪個模組變了」的模組圖,兩個「快」相乘,才有那個近乎即時的 HMR 體驗。PostCSS 途徑因為多了一層 CSS AST 的序列化開銷、且 HMR 依賴框架自己的機制,會稍慢一些但依然夠用;CLI 的 --watch 是檔案輪詢重建,速度中等,適合對即時性要求不高的靜態場景。理解這三者的效能梯度,你就懂了官方為何這樣排推薦順序。
@import "tailwindcss" 與 @source:v4 的 CSS 入口
v4 最有感的一個改變,是設定的重心從 JS 檔搬進了 CSS 檔。這裡有兩個必懂的關鍵字。
@import "tailwindcss" 是 v4 的 CSS 入口起手式,一行就把 Tailwind 全部帶進來:
/* v4:一行搞定,取代 v3 的三行 @tailwind 指令 */
@import "tailwindcss";
對比 v3 你得寫三行、分別注入三層樣式:
/* v3 的舊寫法:升級 v4 時要換成上面那一行 */
@tailwind base;
@tailwind components;
@tailwind utilities;
這是升級 v4 最常見的坑——忘記把三行 @tailwind 換成一行 @import "tailwindcss",結果什麼樣式都編不出來。記住:v4 用標準 CSS @import,v3 用 @tailwind 指令。
@source 則是「內容掃描」的手動校正閥。前面說過 Oxide 會自動偵測內容,九成場景你什麼都不用做。但有兩種例外需要 @source 出手:
@import "tailwindcss";
/* 情況一:把預設掃描範圍外的來源納入(例如第三方 UI 套件) */
@source "../node_modules/@my-ui/components";
/* 情況二:反向排除會誤判的路徑 */
@source not "../legacy/vendor.js";
換句話說,@source 是自動偵測的「補丁」:預設夠聰明,只有當它掃不到(來源在預設範圍外)或掃太多(誤納入不該掃的檔案)時,你才手動出手。這跟 v3 那個「一開始就必須手動列滿路徑」的 content 陣列,是完全不同的心態——v4 是「預設全自動,例外才補設定」。
v4 vs v3:設定心態的整體轉變
把上面幾個點合起來看,你會發現 v3 到 v4 不只是「換了幾個套件名」,而是整個「設定重心」搬了家。這對從 v3 升級的人特別重要,值得單獨對照一次:
| 面向 | v3(舊) | v4(新) |
|---|---|---|
| 安裝套件 | tailwindcss 本體當 PostCSS plugin | 拆成 @tailwindcss/vite、@tailwindcss/postcss、@tailwindcss/cli |
| 初始化 | npx tailwindcss init -p 產生設定檔 | 無 init,設定直接寫進 CSS |
| CSS 入口 | 三行 @tailwind base/components/utilities | 一行 @import "tailwindcss" |
| 內容掃描 | 手動維護 content: [...] 陣列 | Oxide 自動偵測,例外才用 @source |
| 設計 token | tailwind.config.js 的 theme.extend | CSS 裡的 @theme { ... } |
| 前綴/壓縮 | 手動裝 autoprefixer、cssnano | Lightning CSS 內建 |
一句話總結這個轉變:v3 的設定住在 JS(tailwind.config.js),v4 的設定住在 CSS(@theme、@source)。v4 甚至不再提供 init 指令來產生設定檔——因為根本不需要那個檔案了。如果你手上有大量 v3 的 JS 設定不想立刻搬,v4 提供 @config "./tailwind.config.js" 作為過渡橋樑,能繼續讀舊設定,但官方建議的長期方向,是逐步把設定收斂進 CSS。
一個要避開的岔路:CDN 只適合原型
順帶釐清一個常被誤用的「第四條路」:Play CDN(<script src="https://cdn.tailwindcss.com">)。它確實能讓你在一個 HTML 檔裡不裝任何東西就用 Tailwind,很適合 CodePen、快速試玩或教學截圖。但它執行時才在瀏覽器掃描 DOM 生成樣式,效能差、無法完整使用 @theme 自訂、也沒有 tree-shaking(整包 CSS 都載),因此絕不該用於正式環境。正式專案一律走前面三條建置途徑之一。把 CDN 當成「原型專用的臨時通道」看待就對了,別讓它混進生產。
實作範例
理論看完,把三種途徑各實作一次。前提是每種途徑的 CSS 入口都會用到那行 @import "tailwindcss";,差別在建置工具的接法。
範例一:Vite Plugin(最推薦)
Vite 專案的首選。安裝兩個套件,在 vite.config.ts 掛上 plugin,CSS 入口寫一行 import,結束——不需要 postcss.config,也不需要列 content:
# 安裝 Tailwind 與官方 Vite plugin
npm install tailwindcss @tailwindcss/vite
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react"; // 或 vue()、svelte() 等
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [
react(), // 你的框架 plugin
tailwindcss(), // Tailwind v4 Vite plugin,順序放後面即可
],
});
/* src/index.css:CSS 入口 */
@import "tailwindcss";
/* 順手用 @theme 定義設計 token(取代 v3 的 tailwind.config.js) */
@theme {
--color-brand: oklch(55% 0.2 250);
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
}
這段的重點有三。tailwindcss() 掛進 plugins 陣列即可,它會自動接管 CSS 處理,通常放在框架 plugin 之後。CSS 入口只需一行 @import "tailwindcss",Oxide 會自動掃描專案內容,你不必寫 content。設定進了 CSS——@theme 區塊裡定義的 --color-brand 會自動變成 bg-brand、text-brand 等工具類別,設計 token 與樣式住在同一個檔案。這條路的開發體驗最好:改一個 class,Vite HMR 毫秒級把新樣式注入瀏覽器,不重整頁面。
範例二:PostCSS Plugin(Next.js 與通用框架)
框架不走 Vite(最典型是 Next.js App Router,底層是 Webpack/Turbopack)時的選擇。安裝三個套件,在 postcss.config.mjs 掛上 plugin:
# 安裝 Tailwind、PostCSS plugin 與 postcss 本體
npm install tailwindcss @tailwindcss/postcss postcss
// postcss.config.mjs(ESM,v4 推薦格式)
export default {
plugins: {
"@tailwindcss/postcss": {},
// 注意:v4 不需要手動加 autoprefixer,Lightning CSS 已內建
},
};
/* app/globals.css:Next.js 的 CSS 入口,同樣一行 import */
@import "tailwindcss";
@theme {
--color-primary-500: oklch(55% 0.2 250);
--radius-lg: 0.75rem;
}
拆解一下。掛的是 @tailwindcss/postcss,這是 v4 專屬的獨立 plugin 套件,和 v3 直接掛 tailwindcss 本體不同(見下方 v3 對照)。不用加 autoprefixer——這是 v4 相對 v3 最有感的簡化,vendor prefix 由 Lightning CSS 自動處理。CSS 入口一樣是 @import "tailwindcss",和 Vite 途徑完全一致。
對比 v3 的 PostCSS 設定,差異很清楚:
// ❌ v3 的舊 postcss.config.js:掛 tailwindcss 本體,還要手動加 autoprefixer
module.exports = {
plugins: {
tailwindcss: {}, // v3 直接用 tailwindcss 套件
autoprefixer: {}, // v3 需要手動補 vendor prefix
},
};
升級 v4 時,把 tailwindcss 換成 @tailwindcss/postcss、移除 autoprefixer,再把 CSS 裡的 @tailwind 三行換成一行 @import "tailwindcss",三步到位。
範例三:Tailwind CLI(無框架靜態場景)
純靜態 HTML、後端模板、快速原型——沒有 JS 建置流程時的選擇。不需要任何設定檔,靠指令參數指定輸入輸出:
# 安裝 CLI
npm install @tailwindcss/cli
# 開發:監聽模式,存檔即重建
npx @tailwindcss/cli -i ./src/input.css -o ./dist/output.css --watch
# 上線:壓縮輸出(Lightning CSS minify)
npx @tailwindcss/cli -i ./src/input.css -o ./dist/output.css --minify
/* src/input.css:CLI 的輸入檔,依舊一行 import */
@import "tailwindcss";
實務上把指令寫進 package.json 的 scripts,用起來更順手:
{
"scripts": {
"dev:css": "tailwindcss -i src/input.css -o dist/output.css --watch",
"build:css": "tailwindcss -i src/input.css -o dist/output.css --minify"
},
"devDependencies": {
"@tailwindcss/cli": "^4.0.0"
}
}
CLI 的心法是 -i(input,輸入的 CSS 入口)配 -o(output,產出的 CSS 檔),HTML 直接 <link> 這個 output 就好。--watch 讓你存檔即重建(搭配 live-server 之類看效果),--minify 在上線時壓縮。注意 CLI 不支援真正的 HMR,--watch 是檔案監聽重建,速度中等但完全夠用於靜態場景。這三個範例的 input.css 內容其實一模一樣,再次印證:入口 CSS 都是那行 @import,差別只在誰來建置。
把三個範例並排看,你會發現一個很療癒的一致性:不管走哪條路,CSS 入口永遠是 @import "tailwindcss",設計 token 永遠寫在 @theme 裡。真正變動的只有「怎麼把建置工具接上去」——Vite 是掛 plugin、PostCSS 是掛 plugin、CLI 是給指令參數。這代表你在不同專案間切換時,腦中要調整的其實很少;而且哪天專案從靜態 HTML 長成 Vite 應用,你的 CSS 幾乎原封不動,只是換個接法而已。這種「樣式與建置解耦」的設計,正是 v4 想帶給你的順暢感。
常見錯誤與最佳實踐
坑一:選錯途徑,或給 Vite 專案硬套 PostCSS
最常見的浪費,是沒搞清楚專案跑在什麼上面就亂選。給一個明明跑在 Vite 上的專案硬去配 postcss.config + @tailwindcss/postcss,雖然能動,但你白白放棄了 @tailwindcss/vite 更快的增量建置、更緊的 HMR 整合、以及「零 PostCSS 設定」的簡潔:
// ❌ Vite 專案卻走 PostCSS:能動,但放棄了 Vite plugin 的所有優勢
// postcss.config.mjs
export default { plugins: { "@tailwindcss/postcss": {} } };
正確做法:先問「專案的建置工具是什麼」再選途徑。Vite → @tailwindcss/vite;Webpack/Turbopack(Next.js)→ @tailwindcss/postcss;無建置流程 → @tailwindcss/cli。順著建置工具走,你會走到最短、最快的那條路。特別提醒 Astro 使用者:v4 請用官方 @tailwindcss/vite(或 npx astro add tailwind 自動配置),舊的 @astrojs/tailwind 整合對 v4 已棄用,還留著會導致功能異常。
坑二:忘記把 @tailwind 換成 @import
從 v3 升級或照舊教學抄設定時,CSS 入口還留著 v3 的三行 @tailwind 指令,結果 v4 引擎編不出任何樣式,畫面全裸:
/* ❌ v4 專案卻用 v3 的入口寫法 → 樣式全失效 */
@tailwind base;
@tailwind components;
@tailwind utilities;
正確做法:v4 的 CSS 入口一律用標準 @import:
/* ✅ v4 正確入口 */
@import "tailwindcss";
一行取代三行。這是升級 v4 的必改項,漏了它,後面所有設定都是白搭。
坑三:誤以為 v4 還要手動維護 content,或該用 @source 卻沒用
兩個方向的誤解。其一,把 v3 那套「手動列滿 content 路徑」的習慣帶進 v4,到處找 content: [...] 要填——v4 的 Oxide 已自動偵測,多數專案根本不用碰。其二,反過來,樣式來源明明在 node_modules 的第三方套件裡(超出預設掃描範圍),卻沒用 @source 納入,結果那些 class 被當成沒用到而被略過,樣式莫名其妙缺一塊:
/* ❌ 用到第三方套件的 class,卻沒告訴 Tailwind 去掃它 → 樣式缺失 */
@import "tailwindcss";
/* (第三方 UI 套件的 class 全被漏掉) */
正確做法:預設信任自動偵測,只在例外時用 @source 校正。要納入預設範圍外的來源就 @source "../node_modules/@my-ui/components";;要排除誤判路徑就 @source not "..."。記住 @source 是補丁,不是每個專案都要寫。另外,動態拼接的 class(如 `text-${size}`)無論如何都掃不到,那要靠寫完整字串或安全清單解決,是另一回事。
坑四:v4 還在裝 autoprefixer 和 postcss-import
照著舊教學,npm install 時順手把 autoprefixer、postcss-import 也裝了,並掛進 postcss.config——這在 v4 是多餘的,甚至可能和 Lightning CSS 的處理打架:
// ❌ v4 還手動掛 autoprefixer / postcss-import → 多餘且可能衝突
export default {
plugins: {
"postcss-import": {},
"@tailwindcss/postcss": {},
autoprefixer: {},
},
};
正確做法:v4 只掛 @tailwindcss/postcss 一個就好。vendor prefix、@import 打包、CSS 壓縮全由內建的 Lightning CSS 處理,不用也不該再手動裝 autoprefixer 與 postcss-import。相依變少、設定變乾淨,正是 v4 的設計意圖。
最佳實踐小結
- 順著建置工具選途徑:Vite →
@tailwindcss/vite;Next.js/Webpack →@tailwindcss/postcss;無框架 →@tailwindcss/cli。 - CSS 入口用
@import "tailwindcss":v4 一行取代 v3 三行@tailwind,升級必改。 - 內容偵測交給 Oxide:預設自動掃描並尊重
.gitignore,只在例外時用@source校正。 - 別再裝 autoprefixer/postcss-import:v4 內建 Lightning CSS 全包了,PostCSS 途徑只掛一個 plugin。
- 設定搬進 CSS:用
@theme定義設計 token,設定與樣式同檔,取代 v3 的tailwind.config.js(需過渡可用@config引入)。
小結
這是 TailwindCSS 完整教學 系列的第三十七篇。上一篇《回饋模式》,我們把 Modal、Toast、Tooltip 與 skeleton 等回饋 UI 一次做齊,收束了元件模式的旅程;這一篇,我們把視線從「怎麼寫 class」拉到「怎麼把 Tailwind 接進真實專案」——看它如何與各種建置工具協作。回顧幾個重點:
- 三種安裝途徑:
@tailwindcss/vite(Vite 專案首選)、@tailwindcss/postcss(Next.js/Webpack 通用)、@tailwindcss/cli(無框架靜態),產出等價,順著建置工具選就對。 - Oxide 與 Lightning CSS:Oxide(Rust)負責自動偵測內容與增量生成樣式,Lightning CSS 負責加前綴、打包
@import與壓縮,合力讓 v4 快數倍到百倍。 - v4 的 CSS 入口:用
@import "tailwindcss"取代 v3 三行@tailwind;用@source在例外時校正內容掃描;設定用@theme搬進 CSS。 - v3 差異:v3 掛
tailwindcss+ 手動autoprefixer+init產生設定檔;v4 全免,只掛獨立 plugin、內容自動偵測、設定進 CSS。
至此,我們正式開啟 TW-7 生態系與整合 的旅程——把 Tailwind 從語法層帶到工程層。下一篇《效能最佳化》,將接著這條線深入:當 Tailwind 已經順利接進專案後,如何進一步壓小 bundle、加速建置、調校 CSS 產出,讓你的網站不只寫得快,也跑得快。