UnoCSS比Tailwind快2.5–3.7倍,核心在于跳过AST解析与全量文件扫描,仅对模板中真实类名做O(1)查表匹配和缓存复用,而Tailwind JIT必须递归扫描、AST解析、正则匹配三步全量执行。

UnoCSS 编译更快,不是因为它“解析得快”,而是它根本**不解析 AST、不扫描全量文件、不递归匹配正则**——只对模板中真实出现的类名做 O(1) 查表。Tailwind 的 JIT 每次 HMR 都得重跑整套流程,UnoCSS 多数时候只加几行 CSS。
UnoCSS 跳过 AST 解析,Tailwind 必须走完三步
Tailwind 的构建链是刚性的:content 配置 → 全量文件 I/O → 每个文件 AST 解析(PostCSS + css-tree)→ 提取所有疑似类名 token → 对每个 token 逐条匹配数百条正则规则。哪怕你只改了一个 class="text-red-500",它也要重新扫一遍 src/**/*.{ts,tsx,vue} 下全部文件。
UnoCSS 默认不碰 AST:Vite 插件在 transform 阶段直接从 class 属性值字符串里用预编译正则提取类名(如 text-red-500),然后查内存缓存或规则表生成 CSS。没有 AST 解析开销,也没有 glob 扫描延迟。
- 启用
@unocss/transformer-directives后才会解析 CSS 文件 AST,但仅限你import的那几个 CSS 文件,不会扩散到整个项目 - Tailwind 的 AST 解析是强制、全局、不可跳过的;UnoCSS 是按需、局部、可关闭的
- 实测冷启动:相同 1656 个工具类 +
@apply场景下,UnoCSS 328.39 ms,Tailwind 798.42 ms(75%分位数)
动态类名处理差异决定 HMR 响应手感
HMR 阶段的体验差异常被忽略——它不体现在毫秒数字里,而在于你改完 class 回车后,光标有没有卡住。
Tailwind JIT 在组件更新时,只要文件内容变动,就触发全量 re-scan + re-AST + re-match;大型项目下常卡 300–400ms。UnoCSS 只需检查当前文件中新增/删减了哪些字面量类名,命中缓存就直接注入,未命中才查一次规则表。
-
class="p-4 text-${color}-500"这种写法,UnoCSS 的@unocss/extractor-regex能提取出p-4,但无法推断text-${color}-500——和 Tailwind 一样需要safeList或正则兜底 - 但如果你写的是纯字面量,比如新增
bg-emerald-300,UnoCSS 通常1–2ms内完成匹配并注入,Tailwind 则要等完整扫描链跑完 - 删掉一个已用类名(如移除
hover:scale-110),UnoCSS 不会回删 CSS(默认行为),Tailwind 也不会自动剔除——两者都依赖构建时的 content 重分析
缓存策略与构建粒度让 UnoCSS 更“轻”
UnoCSS 的缓存是两级的:内存缓存(dev 时单次请求内复用)+ 磁盘缓存(.unocss-cache,用于构建和 CI)。它缓存的是「类名 → CSS 字符串」映射,不是文件内容哈希。
Tailwind 的缓存基于文件内容哈希和依赖图,一旦任一 content 文件变动,就得清空并重算整个 CSS 块;UnoCSS 只需更新变动文件涉及的类名子集。
- 你删掉一个组件文件,UnoCSS 完全无感;Tailwind 仍会扫描它(直到下次 clean cache)
- UnoCSS 构建产物体积更小,主因不是压缩率高,而是压根没生成未使用的变体组合(如
group-hover:disabled:underline) - 务必禁用
Vite的.vite/deps和 UnoCSS 的.unocss-cache再测冷启动,否则倍数对比失真
真正容易被忽略的是:UnoCSS 的速度优势在「开发中频繁改 class」时才最明显,而这个阶段恰恰最难被 benchmark 捕捉——它靠的是你手指停顿感,不是控制台里跳出来的毫秒数。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











