Tailwind CSS JIT 编译器是什么?有哪些优势?
Tailwind CSS 的 JIT(Just-in-Time)编译器可以理解成“看到你用了哪个类,就生成哪个 CSS”。它不会提前把所有可能的工具类一次性打包出来,而是扫描项目里的模板、组件和脚本文件,只为实际出现的类名生成样式。
需要纠正一个常见说法:JIT 在 Tailwind CSS v2.1 作为预览功能引入,当时需要手动配置 mode: 'jit';从 Tailwind CSS v3 开始,JIT 已经成为默认编译方式,不再需要写 mode: 'jit'。
JIT 编译器是怎么工作的?
Tailwind 的 JIT 流程大致分成三步:扫描 content 配置指定的文件,提取完整类名,然后按需生成 CSS。
jsmodule.exports = { content: ['./src/**/*.{html,js,ts,jsx,tsx,vue,svelte,mdx}'], theme: { extend: {} }, plugins: [], }
在 Tailwind CSS v3+ 中,不要再加 mode: 'jit',这已经是默认行为。
它和旧的 AOT / Purge 模式有什么区别?
早期 Tailwind 更接近 AOT:先生成大量可能用到的工具类,再通过 PurgeCSS 移除没用到的部分。这会导致开发环境 CSS 文件很大、构建和热更新更慢、生产环境还要依赖 purge 配置清理无用样式。
JIT 改成了反过来的方式:先看你实际写了什么类,再生成对应样式。所以在 Tailwind CSS v3 之后,content 扫描就是核心配置,Purge 不再是一个单独步骤。
JIT 的主要优势是什么?
JIT 只处理项目中真实出现的类名,不需要提前生成完整工具类集合。开发时新增一个类,Tailwind 只补生成这一小段 CSS,通常比旧模式轻很多。
因为只生成用到的样式,最终 CSS 体积通常会更可控。前提是 content 路径写对,如果组件目录没被扫描到,对应样式也不会生成。
JIT 还让任意值写法变得实用:
html<div class="w-[137px] bg-[#1da1f2] text-[13px]">自定义样式</div>
这类写法适合少量特殊样式。如果某个值会反复出现,仍然建议放进 theme.extend,否则维护会越来越散。
JIT 也可以按需生成复杂变体组合:
html<button class="hover:bg-blue-500 focus:ring-2 active:scale-95 disabled:opacity-50">按钮</button>
动态类名为什么经常失效?
JIT 扫描的是源码里的完整类名字符串,不是运行时结果。下面这种写法通常无法被正确识别:
jsxconst size = 'lg' return <div className={`text-${size}`}>内容</div>
更推荐写成完整映射:
jsxconst sizeMap = { sm: 'text-sm', lg: 'text-lg', xl: 'text-xl' } return <div className={sizeMap[size]}>内容</div>
如果类名确实来自接口、CMS 或用户配置,可以使用 safelist:
jsmodule.exports = { content: ['./src/**/*.{js,jsx,ts,tsx,vue,html}'], safelist: [ 'bg-red-500', { pattern: /bg-(red|green|blue)-500/, variants: ['hover', 'focus'] }, ], }
使用 JIT 时要注意什么?
content 路径要覆盖完整,Monorepo 里要把共享包也加进去。不要滥用字符串拼接。任意值别当主题系统用,w-[137px]、bg-[#1da1f2] 适合个别特殊值,品牌色、字号、间距这种长期复用的值应该沉淀成设计 token。
Tailwind CSS v4 延续了按需生成的思路,并引入了新的高性能引擎。可以这样理解:v2.1 预览引入 JIT,v3 默认启用 JIT,v4 继续强化引擎性能和现代 CSS 工作流。JIT 的价值很明确:更快的开发体验、更小的 CSS 输出、更灵活的任意值和变体写法,但它要求你写出可被静态扫描到的完整类名。