Tailwind CSS JIT 模式未生效的最直接判断依据是终端未输出“Using JIT mode”;需确认版本为 v3.x、删除已废弃的 mode/purge 配置、显式设置 TAILWIND_MODE=watch、content 路径必须准确且为数组、避免动态 class 拼接,并检查构建工具链是否干扰监听。

Tailwind CSS JIT 模式在开发时“不生效”,90% 的情况不是 JIT 坏了,而是它压根没跑起来——终端没打印 Using JIT (Just-In-Time) mode,就等于你还在用全量编译流程,热更新卡、构建慢、样式漏,全是表象。
终端没显示 “Using JIT mode” 就等于没启用
这是最硬的判断依据。没有这行输出,其他排查都是徒劳。
- 运行
npx tailwindcss -v,确认输出是v3.x.x(如v3.4.3);v2.x或残留@tailwindcss/jit包会强制降级 -
tailwind.config.js中若还存在mode: 'jit'、mode: 'aot'或purge字段,全部删掉——v3+ 已废弃,写了反而禁用 JIT - 启动命令里必须显式加
TAILWIND_MODE=watch,尤其在 Craco、Umi、Vite 自定义脚本中:"dev": "TAILWIND_MODE=watch vite"(Windows 用cross-env TAILWIND_MODE=watch vite)
content 路径写错 = JIT 失明
JIT 不猜代码在哪,只读 content 数组里写的路径。漏一个文件、错一个扩展名,对应 class 就彻底不进编译流水线。
-
content必须是数组,不能是字符串:["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"]✅;"./src/**/*.tsx"❌ - Vue 项目要包含
.vue:["./src/**/*.{js,jsx,ts,tsx,vue}"];Next.js 双路由需同时覆盖app/**/*和pages/**/* - 静态 HTML 入口(如
public/index.html)必须显式列出,否则里面写的class="text-red-500"JIT 根本看不到 - 避免
./**/*.js这类宽泛写法——它会扫node_modules和dist,I/O 拖垮监听响应
PostCSS 插件顺序或构建工具拦截了监听
JIT 依赖构建工具把文件变更事件推过来。插件顺序错、配置文件多余、或工具链绕过 PostCSS 流程,都会让热更新失效。
立即学习“前端免费学习笔记(深入)”;
- Next.js 用户:**不要写
postcss.config.js**——它会覆盖框架内置配置,禁用 JIT 自动路径推导;真要自定义,确保tailwindcss是第一个插件 - Vite 用户:检查是否禁用了
css.preprocess,或用 esbuild 处理 JSX 时漏掉了模板字符串里的className(如className={`p-4 ${isActive ? 'bg-blue-500' : ''}`}) - Docker / Dev Container 环境:inotify 默认不可用,监听器收不到变更信号;加
--poll参数或设TAILWIND_MODE=watch强制轮询
动态 class 拼接让 JIT 完全失效
JIT 是静态分析器,不执行 JS,只认字符串字面量。模板字符串、变量插值、连字符拼接,都会导致对应类名从生成结果里消失。
- ❌
class="${prefix}-red-500"、:class="`bg-${color}-500`"→ JIT 看不到完整类名 - ✅ 改用条件对象:
className={size === 'sm' ? 'text-sm-500' : 'text-lg-500'} - ✅ 或用
clsx:className={clsx({ 'text-sm-500': size === 'sm' })} - 高频动态值可白名单兜底:
safelist: [/text-(sm|lg|xl)-\d+/],但改完必须重启开发服务器才生效
真正容易被忽略的是:JIT 的“生效”不只看配置,它极度依赖构建工具链的完整协作。哪怕 tailwind.config.js 写对了,postcss.config.js 多一行、Vite 的 optimizeDeps.include 漏一个包、Docker 里 inotify 没开,都可能导致 JIT 静默退化——所以排查时别只盯配置文件,得顺着启动日志、文件监听行为、最终生成的 CSS 文件一层层验证。



















