feat: unocss-plugin 支持 wx:class 对象写法中的类名扫描 - #2519
Conversation
修复 unocss-plugin 无法处理 wx:class="{{ { 'ml-17rpx': flag } }}" 对象写法的问题。
模板编译阶段 transDynamicClassExpr 会将 wx:class 对象 key 中的特殊字符
编码为合法 identifier(如 ml-17rpx → ml_da_17rpxMpxEscape),导致 unocss-plugin
扫描编译产物时 parseStrings 无法识别,对应 CSS 不会被生成。
新增 parseMpxEscapeKeys,通过正则扫描 MpxEscape 结尾的 identifier key,
用 unescapeKey 还原原始类名后交给 transformClasses 处理,再重新编码写回 wxml。
支持的写法:
- wx:class="{{ { 'ml-17rpx': flag } }}" — 普通类名
- wx:class="{{ { 'h-100%': true } }}" — 含特殊字符的类名
- wx:class="{{ { 'ml-17rpx h-100%': flag } }}" — key 中空格分隔的多个类名
- wx:class="{{ { '*card': flag } }}" — alias 展开
同步重构 trans-dynamic-class-expr.js:
- mpEscape → escapeClassName,keyEscape → escapeKey,新增对应的 unescape 函数
- 硬编码字符串提取为具名常量(KEY_ESCAPE_SUFFIX/DASH/SPACE)
- escapeReg 改为从 classNameEscapeMap 动态生成,保持 map 和 reg 同步
- classNameDecodeReg 按 token 长度降序排列,避免短 token 优先匹配
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
当前 classNameDecodeMap 的所有 key 互不重叠,无需按长度降序排列。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| }) | ||
| parseMpxEscapeKeys(exp).forEach(({ result, start, end }) => { | ||
| const expanded = transformClasses(result, classNameHandler) | ||
| expSource.replace(start, end, escapeKey(escapeClassName(expanded))) |
There was a problem hiding this comment.
escapeClassName 这里应该不用再做一次这个了,transformClasses的结果应该就已经escape过了
| unknown: '_u_', | ||
| ...escapeMap | ||
| } | ||
| escapeMap = Object.assign({}, mpEscapeMap, { unknown: '_u_' }, escapeMap) |
There was a problem hiding this comment.
去除外部传入的escapeMap逻辑,不再接受外部传入
…feat-unocss-dynamic-class
hiyuki
left a comment
There was a problem hiding this comment.
本轮 review 发现两个问题:
-
hasUnoCSS是 compilation 级全局开关,但 UnoCSS 对模板的资产处理仍受scan.include/exclude限制。当前模板编译器在hasUnoCSS为 true 时会对所有资源跳过transDynamicClassExpr,而processAssets只会重写命中 scan 规则的模板。默认 scan 仅包含src/**/*,因此 npm 组件、src外资源或被显式 exclude 的模板不会经过任一侧的 key 编码。例如被排除模板中的
wx:class="{{ { 'foo-bar': flag } }}"最终仍会输出:<view class='{{_s_.c("", ({ "foo-bar": flag }))}}'/>
未启用 UnoCSS 时则会正确输出
foo_da_barMpxEscape。建议仅对确定会被 UnoCSS 资产阶段处理的资源跳过模板编译器转换,或者让资产阶段对未扫描模板继续执行基础 key 编码,并补充scan.exclude/src外资源的回归测试。 -
移除
escapeMap配置及api/compile.md#escapemap后,docs-vitepress/articles/2.9-release.md和docs-vitepress/articles/2.9-release-alter.md仍明确说明用户可以传入该配置,并继续链接已删除的锚点;这与当前指南中“不支持自定义”的说明冲突。请同步更新这两处历史说明,或提供明确的废弃/迁移说明。
|
已按建议修复 hasUnoCSS 全局开启但部分模板未经过 UnoCSS 扫描的问题:
修复提交:c81fdc51e |
| * @param {boolean} objectKey | ||
| * @returns {{start: number, end: number}|undefined} | ||
| */ | ||
| function findOriginalClassLoc (source, className, objectKey) { |
There was a problem hiding this comment.
这个源码定位逻辑太重了感觉没必要,且不是根据sourceMap来定位的,而是根据匹配?
There was a problem hiding this comment.
维护成本过高,还是以实现功能进行最小改动为目标吧,错误定位溯源不是本期目标
hiyuki
left a comment
There was a problem hiding this comment.
复核最新 head e6a87a2 后,上轮两个问题仍未关闭,建议修复后再合并:
-
hasUnoCSS 仍是 compilation 级全局开关,但 UnoCSS 的模板资产处理继续受 scan.include/exclude 限制。transDynamicClassExpr 在 hasUnoCSS 为 true 时会对所有资源延迟特殊字符转换,而 processAssets 只重写命中 scan 的模板。因此,被 scan.exclude 排除、位于默认 src/**/* 之外或来自 npm 的模板中,类似 wx:class 对象 key hover:bg-red-100 的冒号仍会保留在字符串 key 中,既没有转换成目标 WXS 所需的合法标识符,也不会由 UnoCSS 资产阶段补齐。当前修改只保留了短横线和空格的基础编码,没有覆盖其他特殊字符。建议将延迟转换的判断细化到资源级,或确保未扫描模板仍执行基础 key 编码,并补充 scan.exclude / src 外资源的回归测试。
-
本 PR 删除了 escapeMap 配置实现以及 api/compile.md#escapemap 锚点,但 docs-vitepress/articles/2.9-release.md 和 docs-vitepress/articles/2.9-release-alter.md 仍说明用户可以传入该配置并链接已删除锚点。请同步更新这两处说明,或补充明确的历史版本/迁移说明。
|
已根据最新 review 更新:
验证:Webpack Plugin 定向测试 7/7 通过,UnoCSS Plugin 动态 class 测试 6/6 通过,ESLint 与 git diff --check 通过。 提交:c88b4fc6d、d33bd3980 |
新支持的写法包括: