tailwind v3 的 content 数组必须显式列出所有含类名的文件路径,包括 .vue、.mdx、.astro 等扩展名,静态 html 和第三方库源码路径也要纳入,monorepo 中需用 path.resolve 锚定路径,glob 写法须精确匹配磁盘结构,动态 class 名须通过 safelist 显式声明。

content 数组必须显式列出所有含类名的文件路径
Tailwind v3 不解析 import、不执行 JS、不读取运行时拼接的字符串,只按 content 数组里写的路径,用 fast-glob 硬扫源码文本。漏掉一个 .vue 或 .mdx 文件,里面写的 text-blue-600 就直接进垃圾箱。
- 必须写全扩展名:
"./src/**/*.{js,jsx,ts,tsx,vue,html,mdx}",不能只写.js以为能覆盖 JSX/TSX - 静态 HTML 模板(如
public/index.html)也要加进去,否则里面的class="container mx-auto"会被裁掉 - 用了 Astro、Svelte、MDX?对应后缀
.astro、.svelte、.mdx得手动补上 - 第三方 UI 库(如 DaisyUI)若以源码形式放在
node_modules里,其路径也得列进content,否则btn-primary一样消失
Monorepo 中 content 路径必须用 path.resolve(__dirname, ...)
在 pnpm workspace 下,content 里写 "../../packages/ui/src/**" 是危险的——它依赖 process.cwd(),而子包构建时当前目录变了,路径就错位。Tailwind 不认 workspace:shared 这种协议,只认磁盘上真实存在的路径。
- 开头加
const path = require('path'); - 用
path.resolve(__dirname, '../shared/src/**/*.{ts,tsx}')锚定配置文件自身位置,不受执行目录影响 - 绝对不要在根目录放一个全局
tailwind.config.js并让所有子包共用——各包可能用不同版本 Tailwind,content解析行为不一致
glob 写法错误会导致整片目录完全扫不到
fast-glob 对路径大小写、斜杠方向、通配符层级极其敏感。写错一个字符,扫描就失效;开发时样式正常,上线后按钮没 padding,八成是这里错了。
-
**是递归匹配,*只匹配单层:写成"./src/*.{ts,tsx}"扫不到src/utils/helper.ts,得用"./src/**/*.{ts,tsx}" - Windows 下统一用
/分隔路径,避免\被转义;含空格的路径,每个--content值必须单独双引号包裹,比如--content "./pages/**/*.{js,ts}" - 路径必须和磁盘上实际结构完全一致:项目里全是
.jsx,你却写.js,等于白配
动态 class 名必须进 safelist,否则 PurgeCSS 直接忽略
Tailwind v3+ 的 JIT 模式下,开发服务器不裁剪,掩盖了问题;生产构建才真正执行 tree-shaking。JSX 里 className={`p-4 ${isRed ? 'bg-red-500' : 'bg-gray-200'}`} 没问题,但 className={`from-${color}-500`} 中的 from-blue-500 整个字符串从未以字面量出现过,PurgeCSS 根本看不到。
- 简单场景可硬编码:
safelist: ['from-blue-500', 'from-green-600'] - 多变体推荐正则:
{ pattern: /from-(red|blue|green)-(500|600)/ },注意响应式前缀要显式包含,如/^(md|lg):from-red-500$/ - 避免
.*结尾:/from-.*/会意外匹配原生 CSS 属性from-clip,引入冗余样式
.astro 文件或一个 safelist 正则边界,生产环境就可能少几 KB CSS,换来整个按钮失色。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











