purgecss 能自动删除未使用的 css,但默认配置会误删 hover:bg-blue-500、is-open 等动态类名,因其未扫描编译后 js 中的真实 class 字符串,且插件顺序、safelist 正则、tailwind 内置功能适配等细节极易导致白屏或样式丢失。

直接上结论:PurgeCSS 能自动删掉未用 CSS,但默认配置下大概率会把 hover:bg-blue-500、is-open、[data-state=open] 这类真实生效的样式也清空——不是你漏写了 class,是它根本没“看见”这些字符串。
content 路径必须扫编译后 JS,不能扫 .vue/.tsx 源文件
Webpack 插件运行在 vue-loader 或 @babel/preset-react 之前,读到的是原始模板:class="btn {{ type }}-btn",压根没有 primary-btn 这个字面量。而真实 class 出现在最终打包的 .js 文件里(比如 createElement('div', { class: 'btn primary-btn' }))。
- 别用
glob.sync('./src/**/*.vue'):Windows 下路径分隔符错乱,且扫的是未处理文本 - 改用绝对路径 + 编译产物:
path.join(__dirname, 'dist', '**', '*.js')(前提是构建时关掉devtool: 'source-map',否则 source map 会污染类名匹配) - 更稳妥方案:启用
purgecss-webpack-plugin的modules: true选项,它能通过 AST 解析识别动态拼接逻辑
PostCSS 插件顺序错一位,CSS 就全空
构建后 CSS 文件只剩 @charset "UTF-8";,或 Lighthouse 显示 “CSS 规则数为 0”,基本就是顺序崩了。原因在于 cssnano 提前优化了已被 PurgeCSS 删除的选择器,产出损坏规则;或 autoprefixer 加了前缀后,PurgeCSS 匹配不到原始类名。
- 必须严格按此顺序写:
postcss-import→tailwindcss(如有)→@fullhuman/postcss-purgecss→autoprefixer→cssnano -
cssnano必须关掉重复清理:discardUnused: { discardUnused: false },否则和 PurgeCSS 冲突,可能二次误删 - 如果用了
vite-plugin-css-injected-by-js这类 JS 注入 CSS 的插件,它的输出不在content范围内,得手动加进content数组,或禁用该插件
safelist 不写正则,Tailwind 变体和属性选择器必丢
group-hover:text-red-500 失效、[data-state=open] 样式消失、className={`modal ${isOpen ? 'is-open' : ''}` 里的 is-open 被删光——都是默认提取器不认这些模式。
- 加正则保变体:
/^(hover|focus|group-hover|data)-/ - 保属性选择器:
/\[.*\]/ - 保嵌套语法(如
[&_svg]):需自定义defaultExtractor,或直接迁移到 Tailwind v3+ 内置的content配置(推荐) - 别忘开
keyframes: true和fontFace: true,否则@keyframes和@font-face会被连带清除
Tailwind 项目别装 @fullhuman/postcss-purgecss
Tailwind v3+ 自带 Purge 功能,额外装 @fullhuman/postcss-purgecss 不仅冗余,还会和内置逻辑冲突,导致误删或白屏。
- 删掉
postcss.config.js里所有@fullhuman/postcss-purgecss相关配置 - 只保留
tailwind.config.js中的content字段,例如:content: ['./src/**/*.{js,ts,jsx,tsx,vue}'] - 确保该
content路径指向的是源码(不是编译产物),因为 Tailwind 的提取器已适配框架编译流程
真正难的从来不是“怎么配”,而是判断哪些 class 是运行时生成的、哪些是框架编译后才出现的、哪些被 source map 或插件顺序悄悄破坏了匹配逻辑——这些细节一旦漏掉,删掉的就不是冗余 CSS,而是页面本身。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











