概览
@weapp-tailwindcss/merge 是面向小程序生态的 tailwind-merge 运行时封装。它在保留原库全部 API 的基础上,对类名做了小程序合法化转义,并与 weapp-tailwindcss 编译期插件联动,提供稳定的跨端开发体验。
为什么要使用 merge 运行时
- 动态类名更安全:在组件里根据状态拼接类名时,
twMerge会自动剔除冲突项,确保最终样式一致。 - 小程序专属转义:运行时会把诸如
[#ececec]、[length:24rpx]等非法字符转成小程序可识别的占位符,并在编译期再还原。 - 覆盖多个 Tailwind CSS 主版本:
@weapp-tailwindcss/merge针对tailwindcss@4(基于tailwind-merge@3),而@weapp-tailwindcss/merge-v3保持对tailwindcss@3的长期支持,两者 API 完全一致。 - 保留原生 API:
twMerge、twJoin、extendTailwindMerge、createTailwindMerge等函数与原版完全一致,迁移成本低。
为了适配小程序,@weapp-tailwindcss/merge 会在运行时做两件事:
- 先调用
@weapp-core/escape对字符串「去转义」,把已经被编译期处理过的值还原为标准 Tailwind 类名; - 调用原始的
tailwind-merge完成合并后,再重新转义一次,交给小程序端运行。
如果你在纯 Web 项目中使用,请参考下方的「多端项目」章节配置。
运行时矩阵
| 包名 | 适用场景 | 说明 |
|---|---|---|
@weapp-tailwindcss/runtime | 共享依赖 | 封装 escape/unescape、clsx、weappTwIgnore,被下游包复用 |
@weapp-tailwindcss/merge | tailwindcss@4 | 基于 tailwind-merge@3,默认入口 |
@weapp-tailwindcss/merge-v3 | tailwindcss@3 | 基于 tailwind-merge@2,专为老项目保留 |
@weapp-tailwindcss/cva | class-variance-authority | 自动 escape 的 cva() 运行时 |
@weapp-tailwindcss/variants | tailwind-variants | 提供 tv/cn 等扩展能力 |
安装
- npm
- Yarn
- pnpm
- Bun
npm i @weapp-tailwindcss/merge
yarn add @weapp-tailwindcss/merge
pnpm add @weapp-tailwindcss/merge
bun add @weapp-tailwindcss/merge
适用于
tailwindcss@4的项目。若你仍在维护tailwindcss@3,请改为安装@weapp-tailwindcss/merge-v3:
- npm
- Yarn
- pnpm
- Bun
npm i @weapp-tailwindcss/merge-v3
yarn add @weapp-tailwindcss/merge-v3
pnpm add @weapp-tailwindcss/merge-v3
bun add @weapp-tailwindcss/merge-v3
快速上手
import { twMerge } from '@weapp-tailwindcss/merge'
const buttonClass = twMerge(
'px-2 py-1 bg-red hover:bg-dark-red',
'p-3 bg-[#B91C1C]'
)
// => 'hovercbg-dark-red p-3 bg-_hB91C1C_'
同样的写法在 Web 端会得到 hover:bg-dark-red p-3 bg-[#B91C1C]。在小程序里之所以出现 _h、_ 等占位符,是因为运行时完成了转义。weapp-tailwindcss 插件会在编译阶段把这些占位符还原成合法类名。
与 weapp-tailwindcss 的编译期配合
-
weapp-tailwindcss默认把twMerge、twJoin、cva标记为「无需再次转义」的调用点,如果你自定义了函数名(例如把twMerge重命名为cn),需要在配置里补充ignoreCallExpressionIdentifiers。 -
对于模板字符串,可以使用
weappTwIgnore标签跳过编译期处理:import { weappTwIgnore } from '@weapp-tailwindcss/merge'
const raw = weappTwIgnore`text-[#123456]`这个 helper 实际上就是
String.raw,但它可以让插件准确识别并跳过转义。
tailwind-variants 快速体验
@weapp-tailwindcss/variants 提供了 tailwind-variants 的运行时封装,在小程序环境中同样可以使用 tv/cn 输出带转义的类名:
import { tv } from '@weapp-tailwindcss/variants'
const badge = tv({
base: 'inline-flex items-center rounded-full px-2 text-xs font-semibold',
variants: {
tone: {
neutral: 'bg-[#F4F4F5] text-[#18181B]',
success: 'bg-[#DCFCE7] text-[#166534]',
danger: 'bg-[#FEE2E2] text-[#B91C1C]',
},
},
defaultVariants: {
tone: 'neutral',
},
})
badge({ tone: 'success' })
// => 'inline-flex ... bg-_b_hDCFCE7_B text-_b_h166534_B'
更多组合用法、cn 聚合器以及逃逸策略见后文的 cva 与 tailwind-variants 支持 章节。
多端项目:按需控制转义
create 工厂允许你为不同运行时定制 escape 策略:
import { create } from '@weapp-tailwindcss/merge'
const { twMerge: mergeForMiniProgram } = create()
const { twMerge: mergeForWeb } = create({
escape: false,
unescape: false,
})
mergeForMiniProgram('text-[#ececec]', 'text-[#ECECEC]') // → 'text-_b_hECECEC_B'
mergeForWeb('text-[#ececec]', 'text-[#ECECEC]') // → 'text-[#ECECEC]'
escape: false表示结果保持原样(适合 Web 或同构渲染)。unescape: false可跳过运行前的「反转义」,用于确保输入不会被改写。- 如果只想自定义映射表,传入
escape: { map: { '#': '__hash__' } }即可;运行时会把自定义映射与默认映射合并,保证编译期和运行时的行为一致。
在线体验
function () { return <MergeDemo/> }
上方示例允许切换「禁用 escape/unescape」,用来对比运行时转义前后的差异。
