tailwind 生产环境样式丢失主因是 purgecss 白名单配置不准:它只匹配源码字面量,如 md:text-red-500 需显式加入 safelist;正则应覆盖变体前缀与取值,如 /^(?:md|lg|hover):text-red-(?:500|600)$/。

Tailwind 生产环境样式丢失,八成不是 class 写错了,而是 PurgeCSS 把它当“没用”给删了——白名单(safelist)配得不准、不全、不匹配,就是最常见原因。
为什么 safelist 正则总漏掉 md:text-red-500 这类响应式类
PurgeCSS 匹配的是源码中**字面量出现的字符串**,不是运行时渲染结果。你写 md:text-red-500,它只认这个完整字符串;如果源码里只写了 text-red-500,那带 md: 前缀的就不会被扫描到,必须显式保留在 safelist 里。
- 别只写
/^text-red-500$/—— 它完全不匹配md:text-red-500或hover:text-red-500 - 正确写法是把变体前缀也纳入正则:
/^(?:md|lg|hover):text-red-(?:500|600)$/ - 如果前缀和取值组合太多,优先收敛实际用到的范围,比如项目只用
sm/md和red//<code>green,就别写.* - 注意括号和非捕获组
(?:...)的写法,避免正则语法错误导致整个 pattern 失效
动态拼接的 class(如 text-${color}-500)怎么进白名单才安全
JSX 里 className={`text-${color}-500`} 这种写法,PurgeCSS 根本看不到 text-red-500 这个字符串——它只看到模板字面量 text-${color}-500,所以必须靠 safelist 主动兜底。
- 用函数式 pattern 比纯字符串更可控:
{ pattern: /text-(red|blue|green)-\d+/ } - 避免
/text-.*/这种宽泛写法——它会意外保留text-clip、text-overflow等原生 CSS 属性,污染输出 - 如果 color 来自 JSON 配置或 CMS 字段(如
item.classNames = "text-red-500"),这些字符串不会被静态扫描到,也得加进safelist - 优先考虑重构:把动态逻辑收口到组件内部,用
@apply封装成静态类,比依赖白名单更可靠
白名单生效但体积暴增?检查是否误用了通配符
safelist 不是“越宽越好”,写错一个点,可能让几百个未用类逃过清理。
-
/^w-/会保留全部w-*工具类(w-1/2、w-screen、w-max…),体积反弹明显 - 更合理的写法是按实际取值收敛:
/^w-(1\/2|full|fit|auto)$/或/^w-[1-9]$/ - 字符串形式的白名单(如
'bg-opacity-50')只保单个类,适合零星关键类;正则适合批量模式,但必须验证边界 - 启用
debug: true后构建,看控制台输出的preserved类统计——如果某条 pattern 贡献了上千个类,大概率写得太宽了
真正难的不是写正则,而是搞清「哪些 class 是动态生成的、哪些是第三方库注入的、哪些藏在 HTML 模板或 CMS 字段里」——这些地方都不会出现在你的 JSX 字面量中,却都得靠 safelist 手动补全。漏掉任何一个环节,线上就少一种颜色、缺一个断点、丢一套间距。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











