PurgeCSS不会自动精准剔除,其“精准”完全依赖人工配置:content必须覆盖所有类名出现路径(如绝对路径path.join(__dirname, 'src', '**', '*.{js,ts,jsx,tsx,vue,html}')),safelist必须显式保留动态类名模式(如/^(hover|focus|group-hover|data)-/、/\[.*\]/)、第三方库图标类(如/^el-icon-/)及状态类(如is-open),且PostCSS插件顺序须严格为postcss-import→tailwindcss→@fullhuman/postcss-purgecss→autoprefixer→cssnano,否则CSS可能清空或误删。

PurgeCSS 不会自动“精准”剔除——它只删它明确看到的、且没被 safelist 保护的类名;所谓精准,全靠你告诉它哪些文件含真实类名、哪些动态模式必须保留。
content 路径必须覆盖所有 class 出现场所
它不猜、不推断、不执行 JS,只做字符串扫描。漏一个路径,对应类名就可能被清空。
- 别写
./src/**/*.vue—— Windows 下 glob 失效,且漏掉.tsx中的className字符串 - 改用绝对路径:
path.join(__dirname, 'src', '**', '*.{js,ts,jsx,tsx,vue,html}') - 静态 HTML(如
public/index.html)和 Markdown 渲染页(src/content/**/*.mdx)也得加进content数组 - 若用了
vite-plugin-css-injected-by-js这类运行时注入 CSS 的插件,它的输出不在content范围内,必须手动把 JS 文件路径加进去,或禁用该插件
safelist 必须兜住所有动态类名模式
默认提取器只认字面量,class="btn btn--${size}" 里的 btn--sm 根本不会出现,除非你告诉它“所有 btn--* 都留着”。
- Tailwind 变体必须显式放行:
/^(hover|focus|group-hover|data)-/、/\[.*\]/ - 状态类如
is-open、hidden、md:block得进白名单,否则构建后直接消失 - 第三方库图标类(
el-icon-edit、anticon-home)常由 JS 插入,也要加正则,例如/^el-icon-/ - 避免宽泛匹配:
/^bg-/会保下所有背景色,但/^bg-(blue|gray)-[0-9]+$/更安全
PostCSS 插件顺序错一位,CSS 就可能只剩 @charset "UTF-8";
顺序崩了,@fullhuman/postcss-purgecss 会拿到已被 cssnano 处理过的残缺 CSS,或者在 tailwindcss 生成规则前就跑,结果什么都没扫到。
立即学习“前端免费学习笔记(深入)”;
- 严格按此顺序写:
postcss-import→tailwindcss(如有)→@fullhuman/postcss-purgecss→autoprefixer→cssnano -
cssnano必须关掉discardUnused: { discardUnused: false },否则和 PurgeCSS 重复干活,二次误删 - Tailwind v3+ 项目别额外装
@fullhuman/postcss-purgecss——它和内置 JIT purge 功能冲突,删掉postcss.config.js里多余的 purgecss 插件 - 开发时开
devtool: 'source-map'?关掉它,source map 注释会污染类名匹配逻辑
验证是否真生效,不能只看本地 dev 服务
npm run dev 正常 ≠ 生产有效。JIT 在开发模式下是全量供应,掩盖所有配置缺陷。
- 强制走生产流程:
TAILWIND_MODE=build npx tailwindcss -i ./src/input.css -o ./dist/output.css --minify - 检查输出文件大小和内容:用
grep -o "text-lg" dist/output.css | wc -l对比源码中出现次数 - 临时加一行非法类名,比如
className="bg-hotpink text-9xl",再构建——如果输出 CSS 里真出现了,说明 JIT 已退化为全量模式 - 真正难的不是配对一条正则,而是判断
[data-state=open]该进 safelist 还是该重构为data-state属性驱动;工具只处理看得见的,看不见的冗余还在 DOM 里等着你手动拆


















