jit模式本质是“生成更少”而非“编译更快”,它仅按源码中字面量类名生成对应规则,体积可从2mb降至10–30kb;content路径错一位、漏扩展名或未覆盖所有含class文件(如next.js需同时包含app/和pages/),jit即退化为全量输出;动态类名(如text-${color})无法被静态分析捕获,须用@apply封装或safelist精确正则兜底;验证必须走生产构建流程(tailwind_mode=build),通过grep检测冷门类是否被剔除。

JIT模式不是“编译更快”,而是“生成更少”
它不加速构建过程本身,而是让最终输出的 CSS 文件变小——从动辄 2MB 降到 10–30KB 是常态。关键在于:JIT 不预生成所有类(如 text-xs 到 text-9xl、所有断点下的 flex 变体),只扫描你源码里真实出现的类名字面量,然后生成对应规则。
content 配置错一个字符,JIT 就退化成全量输出
这是体积没变小的最常见原因。JIT 完全依赖 content 数组中列出的路径去静态读取文件内容;路径漏写、扩展名不全、带多余前缀,都会导致扫描失败,结果就是默默保留全部类。
-
content: ["./src/**/*.{js,ts}"]→ 漏了.jsx和.tsx,React 组件里的className全被忽略 -
content: ["src/App.tsx"]→ 只扫单个文件,子组件里的bg-red-500不会被捕获 -
content: ["./src/**/*.{js,jsx,ts,tsx}"]→./前缀在 Vite/Next.js 中可能被跳过,应统一用src/**/*.{js,jsx,ts,tsx} - Next.js 项目必须同时包含
app/**/*.{js,jsx,ts,tsx}和pages/**/*.{js,jsx,ts,tsx},否则dark:、group-类大概率丢失
动态类名(如 text-${color})根本不会被 JIT 捕获
JIT 是静态分析工具,不执行 JS,也不推断变量值。它只匹配源码中真实存在的字符串,比如 "text-red-500" 或 'bg-blue-400'。一旦写成拼接形式,这些类就直接进回收站。
- 安全写法:
className={isActive ? "bg-blue-500" : "bg-gray-200"}—— 两个字面量都出现在源码中,能被扫描到 - 危险写法:
className={`p-${padding}`}或class="text-${size}"—— JIT 看不到具体值,不生成任何规则 - 替代方案:优先用
@apply封装,例如.btn-primary { @apply bg-blue-500 text-white; },再确保该 CSS 文件路径加入content - 兜底方案:必须用动态拼接时,在
safelist里写精确正则,如/^text-(red|blue|green)-500$/,避免宽泛匹配/^text-/
验证 JIT 是否真生效,不能靠本地开发服务器
npm run dev 正常 ≠ 生产构建正常。开发服务器是 JIT 实时供应,完全不依赖 content 扫描结果;而 npm run build 才真正触发裁剪逻辑。
- 强制走生产流程:
TAILWIND_MODE=build npx tailwindcss -i ./src/input.css -o ./dist/output.css --minify - 人工注入测试类:在某个被
content覆盖的文件里加className="bg-hotpink" - 检查输出:
grep -o "bg-hotpink" ./dist/output.css—— 若返回非空,说明 JIT 没跑,还在全量打包 - 对比频次:
grep -o "text-lg" ./dist/output.css | wc -l应显著少于源码中实际出现次数(如 120 次 → 8 次)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











