purifycss 不适用于 spa 静态分析,因其仅字符串扫描、不执行 js 或解析 ast,无法识别动态类名;tailwind v3+ 内置 content 配置已替代它,应禁用 purifycss 并用 safelist 保底。

PurifyCSS 本身不是为 SPA 设计的——它只做字符串级扫描,无法识别 className={<code>btn ${isPrimary ? 'btn-primary' : 'btn-secondary'}} 这类运行时拼接的类名,也不会解析 Vue/React 的模板编译结果。直接用它扫 .jsx 或 .vue 源文件,大概率把 hover:bg-blue-500、is-open、active 全删光。
- PurifyCSS 只匹配源码里“明文写出”的 class 字符串,不执行 JS,不解析 AST,不模拟组件挂载
- 它读到的是
class="btn {{ type }}-btn"(Vue SFC)或className={cls}(React),根本看不到primary-btn - 若 content 配了
glob.sync('./src/*<em>/</em>.vue'),Windows 下路径会失效;改用path.join(__dirname, 'src', '*<em>', '</em>.{js,ts,jsx,tsx,vue}')才可靠
purifycss 命令行或 Node API 调用必须传入已展开的 HTML 字符串(含所有路由状态),否则漏删严重。SPA 场景下,你得先用 Puppeteer 或 Playwright 渲染所有路由,再把生成的 HTML 喂给 PurifyCSS——这已超出“静态分析”范畴。
@fullhuman/postcss-purgecss 在 PostCSS 流程中更实用,但前提是:
-
content列表指向编译后的 JS/TS 输出目录(如dist/*.js),而非源码 - 关掉
devtool: 'source-map',否则/<em># sourceMappingURL= </em>/会被误当 class 名匹配 - 插件顺序必须是:
postcss-import→tailwindcss(如有)→@fullhuman/postcss-purgecss→autoprefixer→cssnano -
cssnano必须显式禁用discardUnused:{ discardUnused: false }
Tailwind v3+ 内置的 content 配置(在 tailwind.config.js 中)已覆盖 PurifyCSS 的全部能力,且能正确处理 group-hover:text-red-500、[data-state=open]、[&_svg] 等模式。额外加 @fullhuman/postcss-purgecss 不仅冗余,还会因 extractor 不兼容导致 hover: 类被截断、属性选择器失配。
- 删除
postcss.config.js中所有@fullhuman/postcss-purgecss引用 - 把所有动态类名写进
tailwind.config.js的safelist:/^(hover|focus|active|group-hover|data)-//[.*]//^is-/
- 启用
keyframes: true和fontFace: true,否则@keyframes和@font-face会被清空
purifycss-webpack-plugin 在 Webpack 中基本失效
该插件在 vue-loader 或 @babel/preset-react 处理前就运行,读到的是原始模板字符串,不是最终 class 集合。Webpack 5+ 推荐换用 purgecss-webpack-plugin 并开启 modules: true(启用 AST 解析),但仍有大量边界 case 漏判。
- 更现实的做法:放弃“全自动”,用
safelist显式保底 - 对
className={`modal \${isOpen ? 'is-open' : ''}`}这类,直接加'is-open'到 safelist 数组 - 对第三方 UI 库(如 Ant Design、Element Plus),手动列出你实际用到的组件类名,例如
'ant-btn-primary'、'el-dialog',别指望 PurifyCSS 自动推断
真正难的不是配置,是判断哪些 class 是静态可扫描的、哪些必须靠 safelist 或 AST 提取器兜底。没做这层判断就跑 PurifyCSS,结果往往是样式大面积丢失,而不是体积下降。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











