tailwind css打包未删无用类,根本原因是content配置失效:路径漏写(如缺.jsx/.tsx)、带./前缀解析不稳定、未覆盖ssr/mdx模板,且未执行tailwind_mode=build生产构建;需用grep验证扫描是否生效。

Tailwind CSS 打包后没删无用类,基本等于 content 配置失效了——它不报错,但会安静地输出全部 3000+ 工具类,体积飙到 2MB+。
为什么 content 路径看似写了却没生效?
路径漏写、前缀错误、后缀不全,都会让 JIT 扫描“假装运行”,实则跳过你真正写 className 的文件。
-
./src/**/*.{js,ts}漏掉.jsx和.tsx,React 组件里的text-red-500就不会被识别 -
src/App.tsx这种单文件写法,子组件(如src/components/Button.tsx)完全不在扫描范围内 -
./src/**带./前缀,在 Next.js 或 Vite 中解析不稳定,app/layout.tsx或data/**/*.mdx很可能被跳过 - SSR/静态生成模板(如
views/**/*.html.ejs、content/**/*.mdx)没加进content,服务端渲染出的 class 全部被当“死代码”处理
为什么本地 npm run dev 正常,构建后样式就丢了?
开发服务器是 JIT 实时供应,根本不依赖 content 扫描结果;而 npm run build 完全靠它裁剪。你看到的“正常”,只是掩盖了配置缺陷。
- 没设
TAILWIND_MODE=build,或没加--minify,purge 逻辑压根不启动 - 直接跑
npx tailwindcss -i ./src/input.css -o ./dist/output.css,没走生产模式,等同于全量导出 - 改完
tailwind.config.js后没重启 dev server,缓存仍沿用旧扫描列表
怎么验证 content 是否真在扫描?
别信体积数字,要查实际行为。最可靠的方式是人工注入一个冷门但合法的类,再看它是否出现在输出中。
- 在任意被
content覆盖的文件里加一行:className="bg-hotpink"(hotpink是 Tailwind 默认不带的颜色) - 运行:
TAILWIND_MODE=build npx tailwindcss -i ./src/input.css -o ./dist/output.css --minify - 执行:
grep -o "bg-hotpink" ./dist/output.css—— 如果返回非空,说明 JIT 没跑,还在全量打包;为空才代表扫描已启动 - 再对比高频类:
grep -o "text-lg" ./src/**/* | wc -lvsgrep -o "text-lg" ./dist/output.css | wc -l,后者显著更少才说明裁剪生效
动态类名(如 text-${color})为什么总被删?
Tailwind 不执行 JS,只匹配源码中真实出现的字符串字面量。变量拼接在构建时无法推断,不显式兜底就等于主动放弃样式。
- 优先用
@apply封装:.btn-error { @apply text-red-500; },再把该 CSS 文件路径加进content - 必须保留动态拼接时,在
tailwind.config.js的safelist里写精确正则,例如/^text-(red|blue|green)-500$/,结尾加$防止误匹配text-red-5000 - 避免
/^text-/这种宽泛正则——它会保住全部text-类,体积直接反弹 -
md:text-lg和text-lg是两个独立类,safelist里只写后者,前者仍会被删
真正难的不是定位哪一行配置错了,而是当 content 路径看似覆盖了所有文件,却因 SSR 模板漏加、Monorepo 中相对路径解析偏移、或测试文件干扰导致扫描静默失败——这些地方既不报错,也不提示,只默默保留全部类。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











