2026 年 9 月 1 日,shadcn(shadcn/ui 作者)与 aidenybai(cnfast 作者)联合发布新包 cn(GitHub 仓库 shadcn-ui/cn),定位是 Tailwind 类名合并与冲突消解引擎,用来取代前端项目里最常见的 clsx + tailwind-merge 组合。官方基准给出三个关键数字:组件最典型调用从 320 纳秒降到 10 纳秒(快 30 倍);在 58 个真实开源仓库的 144,265 次调用回放中,几何均值快 37 倍;重复字符串场景快 172 倍。迁移不需要重写代码,npx shadcn@latest migrate cn 一条命令即可完成替换。
它解决什么问题
任何 Tailwind 项目都会写 cn() 这类工具函数:条件类名拼接(clsx 的活)加冲突消解(px-2 与 px-4 同时出现时保留后者,tailwind-merge 的活)。这个函数每个组件每次渲染都在跑,是前端工程中调用频率最高的代码之一,但标准实现一直由两个独立库拼凑而成。
cn 把两件事合并进一个包、统一到一个 cn() 入口:拼接沿用 clsx 的参数语义,冲突消解沿用 tailwind-merge 的规则语义。它不依赖 shadcn/ui,任何 Tailwind v4 项目都能直接使用。
快 30 倍是怎么做到的
性能来自两个机制:
- 参数身份缓存:
cn会记住重复出现的调用序列,同一组件在渲染循环中反复调用时按参数身份直接命中缓存,跳过合并计算。这是重复字符串场景 172 倍提升的主要来源。 - 编译期表:默认冲突规则在构建时编译成查找表,运行时只查表,不解析规则。
官方基准(pnpm bench,每个库独立进程、独立预热、取 5 次最优)分场景对比:
| 场景 | clsx + tailwind-merge | cn | 提升 |
|---|---|---|---|
| 组件最典型调用(稳定类名) | 320 ns | 10 ns | 30× |
| 与上次渲染相同的类名(缓存命中) | 14 ns | 7 ns | 1.9× |
| 上千个重复字符串(真实仓库工作集) | 2.4 µs | 14 ns | 172× |
| 冷渲染、大量任意值 | 3.4 µs | 1.1 µs | 3.0× |
| SSR 风格唯一字符串 | 2.3 µs | 360 ns | 6.4× |
| 页面首次调用 | 3.2 ms | 0.4 ms | 7× |
除合成基准外,项目还回放了 58 个开源代码库的 144,265 次真实调用(pnpm bench:corpus),几何均值比 clsx + tailwind-merge 快 37 倍。
输出与 tailwind-merge 完全一致
官方用 356,000 组差分测试验证:对每个输入,cn 产生与 tailwind-merge 相同的输出。所有导出按原名或熟悉的名字保留:twMerge、twJoin、clsx 从 cn 导出且行为不变;extendTailwindMerge、createTwMerge、defaultConfig、fromTheme、validators、mergeConfigs 从 cn/config 导出。唯一不支持的是 experimentalParseClassName。
如何迁移
- 新项目:
npm i cn,import 后直接用,无需配置。 - 现有 shadcn/ui 项目:运行
npx shadcn@latest migrate cn一键迁移;或手动把lib/utils.ts里的twMerge(clsx(inputs))换成从cn导入的函数,再移除clsx与tailwind-merge依赖。其他包仍在 import 这两个库时,可以把它们 alias 到cn,让打包只带一份实现。 - 主题定制:
cn/config的createCn({ extend, override, prefix })接受与tailwind-merge相同结构的配置,自定义校验器(fromTheme、validators)直接可用;Tailwind v4 前缀配置(prefix选项)同样受支持。
适用边界
- 只支持 Tailwind v4:
cn与tailwind-mergev3 同级,Tailwind v3 项目应留在tailwind-mergev2,暂不迁移。 - 动态拼接类名检测不到:用
p-前缀加变量拼出的类名,cn与 Tailwind 本身一样无法静态识别,需要cn build编译期方案或--safelist。 - 包体积:
cnminified 后 26 KB,是同类方案中解析成本最低的;追求更小可走cn build编译期生成表。 - 运行环境:零依赖、框架无关,浏览器、Node、Bun、Deno、edge 运行时都能跑,React、Vue、Svelte、Solid、Astro 与服务端模板通用;CLI 需要 Node 20 以上。
结论
cn 用参数身份缓存和编译期表把高频的类名合并压到 10 纳秒级,同时用 356,000 组差分测试保证输出与 tailwind-merge 一致——性能提升与行为兼容可以兼得。正在用 clsx + tailwind-merge 的 Tailwind v4 项目,可以把它当作零成本替换:同 API、官方迁移命令、真实仓库基准背书。Tailwind v3 用户则暂时不用动。