首页
/ airi 项目 UnoCSS 实战:用 transformerCompileClass 将多类名编译为单一哈希类,压缩 HTML 体积

airi 项目 UnoCSS 实战:用 transformerCompileClass 将多类名编译为单一哈希类,压缩 HTML 体积

2026-09-08 23:15:39作者:沈韬淼Beryl

导读

本文聚焦 UnoCSS 内置转换器 transformerCompileClass:它能在构建期把元素上一长串工具类(utility class)合并为单一哈希类名(如 uno-qlmcrp),从而显著缩短 HTML 体积、隐藏类名语义并减少浏览器解析开销。文章以 transformers/compile-class 参考文档 为骨架,结合 airi 仓库中实际生效的 uno.config.ts(以及其各子应用的 vite.config.ts 等配置)给出可落地的最佳实践,读者学完后可以立即在自己的 airi 子应用或独立 UnoCSS 项目中启用并定制该转换器。

一、什么是 transformerCompileClass

在 airi 这类大型 monorepo 前端(apps/component-callingapps/stage-webapps/stage-pocketpackages/stage-uidocs 等大量依赖 UnoCSS 的场景)中,模板里常常会写满重复的工具类字符串,例如每个卡片都要重复 "flex items-center justify-center gap-2 text-sm"。这些字符串既占 HTML 体积,也会让每次浏览器解析 class 属性付出额外成本。

transformerCompileClass 解决的问题正是"类名压缩":它以触发前缀(默认 :uno:)标记需要合并的 class 列表,然后在编译阶段把这一组工具类替换成一个根据类名内容哈希生成的短类名,最终为这个哈希类生成对应的完整 CSS。由于它只作用于 HTML / 模板文本本身(而不是扫描整个项目的提取管线),你可以在不影响其他工具类的前提下,按需把高频复用的类组合"编译"掉。

本技能文档来自 SKILL.md 中 UnoCSS 的官方 transformers 章节,源码层面的行为以仓库中 unocss(catalog 版本,声明于 package.json)为准。

二、安装与基础配置

transformerCompileClass 随主包 unocss 一起导出,因此只要项目中已经安装了 unocss(airi 根 package.jsonpackages/stage-ui/package.json 均以 catalog: 形式依赖),就无需额外安装。

uno.config.ts 中通过 defineConfigtransformers 数组开启:

import { defineConfig, transformerCompileClass } from 'unocss'

export default defineConfig({
  transformers: [
    transformerCompileClass(),
  ],
})

与 airi 的实际配置对比:仓库根 uno.config.ts 目前启用了 transformerDirectives(配置了 --at-apply 变量)与 transformerVariantGroup 两个转换器。若在某个对包体积敏感的页面/组件里需要启用类名压缩,将上面的 transformerCompileClass() 追加进同一数组末尾即可,二者互不冲突(叠加规则见下文"与其他 Transformer 组合")。

三、核心用法:用 :uno: 前缀标记可编译类

在模板中,为希望被合并进单一哈希类的 class 添加 :uno: 前缀:

<!-- 编译前 -->
<div class=":uno: text-center sm:text-left">
  <div class=":uno: text-sm font-bold hover:text-red" />
</div>

<!-- 编译后 -->
<div class="uno-qlmcrp">
  <div class="uno-0qw2gr" />
</div>

要点说明:

  • :uno: 前缀只出现在源码中的标记位置,最终产物中不会存在该字符;
  • 编译基于这一组工具类字符串的完整内容做确定性哈希,因此完全相同的类组合会得到完全相同的哈希类名,天然支持复用与缓存;
  • sm:text-lefthover:text-red 这类带变体的工具类同样被正确归并进哈希规则(响应式规则会被抽到对应的 @media 块中,见下文生成 CSS);
  • 未加前缀的普通 class 不受影响,可作为"旁路"继续走常规提取管线。

编译产物对应的 CSS

对上述示例,转换器生成的样式大致如下:

.uno-qlmcrp {
  text-align: center;
}
.uno-0qw2gr {
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 700;
}
.uno-0qw2gr:hover {
  --un-text-opacity: 1;
  color: rgb(248 113 113 / var(--un-text-opacity));
}
@media (min-width: 640px) {
  .uno-qlmcrp {
    text-align: left;
  }
}

可以看到三点实现细节:

  1. 原本 HTML 里的 "text-center sm:text-left" 两个 token,被收拢为一条媒体外规则 + 一条 @media (min-width: 640px) 规则,浏览器只需针对一个类名去匹配;
  2. hover 变体被展开为 .uno-0qw2gr:hover 独立规则,说明转换器内部仍然复用了 UnoCSS 的变体(variants)展开机制,与 core-variants 参考文档 描述一致;
  3. CSS 变量(--un-text-opacity)等 wind 系预设产物保持原样,因此该转换器与 airi 使用中的 presetWind3 等预设完全兼容。

四、全部可配置项(Options)

transformerCompileClass 接受一个对象参数:

transformerCompileClass({
  // 自定义触发字符串(默认:':uno:')
  trigger: ':uno:',

  // 自定义生成的类名前缀(默认:'uno-')
  classPrefix: 'uno-',

  // 自定义类名哈希函数,输入为待编译的类名字符串
  hashFn: (str) => /* custom hash */,

  // 是否在编译后的类名旁保留原始类(默认:false)
  keepOriginal: false,
})

逐项实战解读:

  • trigger:默认 ':uno:'。若与项目中其它标记(例如 attributify 或自定义内容管道)冲突,可改成更独特的字符串,如 ':u:'。该前缀仅作为源码中的"编译标记",不会输出到最终 CSS/HTML;
  • classPrefix:默认 'uno-'。用于区分产物中的哈希类与手写类,便于在调试面板里一眼识别,也可避免与第三方样式表前缀冲突;
  • hashFn:默认是内置哈希(fNV-1a 变体并做短 base36 编码,这里不必依赖具体算法,保证同输入同输出即可)。传入自定义函数时必须保持确定性(纯函数),否则同一段源码在不同构建间会产生不同类名,破坏产物缓存与离线渲染的一致性;若与 SSR/预渲染(airi 的 apps/stage-webdocs 均有静态站点/水合场景)配合,还需保证函数在 Node 与浏览器两端结果一致;
  • keepOriginal:默认 false。调试期可临时置为 true,让源码类名仍以普通类形式保留在元素上(用于人工核对样式),线上构建再关闭以最大化压缩收益。

五、典型使用场景

原文档列出的核心收益在 airi 的规模化组件场景中对应关系如下:

  • 更小的 HTML(Smaller HTML):聊天气泡、按钮组、设置页条目这类高频组件往往带 5~10 个工具类,模板循环渲染时重复字符串会成倍放大体积。将固定样式块用 :uno: 编译为哈希类后,每条记录只输出 uno-xxxxxx 一个 token;
  • 混淆(Obfuscation):生产环境 HTML 中不再暴露 text-centerbg-primary-500 这类与设计语义直接对应的类名,降低模板样式信息被直接扒走的可能。注意这是"减少可读信息"层面的收益,并非安全机制;
  • 性能(Performance):浏览器需要解析的 class 属性 token 数减少;同时由于相同组合只保留一份哈希类定义,CSS 中规则条数与选择器匹配成本相应下降。对需要实时语音、Live2D/Three 渲染等高交互场景(如 packages/stage-uiapps/stage-tamagotchi 的渲染层)可减少 DOM 解析干扰。需要强调的是:文档与仓库均未给出定量基准数据,该收益是结构性的定性优化,不应过度宣传为可测量的性能指标。

六、配套 ESLint 规则:enforce-class-compile

要在一个多人协作、多应用共存的仓库里推行"工具类必须带 :uno: 前缀"的约定,依赖人肉自觉并不现实。@unocss 生态提供了 @unocss/enforce-class-compile 规则(需在项目中引入配套的 ESLint 配置/插件后生效):

{
  "rules": {
    "@unocss/enforce-class-compile": "warn"
  }
}

规则行为:

  • class 属性不以 :uno: 开头时给出警告;
  • 支持自动修复(Auto-fix):为漏标前缀的 class 自动补上 :uno:

也可传参控制细节:

{
  "rules": {
    "@unocss/enforce-class-compile": ["warn", {
      "prefix": ":uno:",
      "enableFix": true
    }]
  }
}

参数说明:

  • prefix:规则检测/补全时使用的前缀字符串,必须与 uno.config.tstransformerCompileClass({ trigger }) 的取值保持一致,否则规则会与转换器"打架";
  • enableFix:是否允许 eslint --fix 自动加前缀,CI 中可以 false + 仅警告,先把存量代码放行,再渐进式迁移。

七、与其他 Transformer 的组合顺序

airi 根 uno.config.ts 已经示范了"多个 transformer 共存"的写法。官方推荐按如下顺序排列:

export default defineConfig({
  transformers: [
    transformerVariantGroup(),  // 先处理变体组
    transformerDirectives(),    // 再处理指令
    transformerCompileClass(),  // 最后执行类名编译
  ],
})

顺序逻辑是:

  1. transformerVariantGroup 先把 hover:(text-red underline)sm:(...) 这类括号组展开成普通工具类(该技能参考见 transformer-variant-group 文档),否则 compileClass 会拿到一个它无法解析的"伪类";
  2. transformerDirectives 再把 @applytheme() 等 CSS 指令就地解析(参考 transformer-directives 文档),这些属于 CSS 层处理,与 class 编译互不干扰;
  3. transformerCompileClass 在最后做纯 class 层面的收敛,这样它处理的对象已经是展开、扁平化后的最终工具类集合,生成的哈希最稳定、漏项最少。

若在 airi 某个子应用(例如新增一个对模板体积敏感的页面应用)启用,直接在 apps/component-calling/uno.config.ts 这类子配置的 transformers 数组末尾 pushtransformerCompileClass() 即可,无需改动根配置。

八、注意事项与仓库内的落地建议

结合 airi 的既有工程实践,补充几条使用边界:

  • 该转换器是编译期、静态的:它只会替换"写死在模板里、带 :uno: 前缀"的 class。若类名来自运行时拼接(例如 :class="cond ? 'text-red' : 'text-gray'"),前缀不会命中,自然也不会被编译,仍走常规提取(unocss 会扫描模板源码中的字符串字面量,参考 core-extracting 文档);
  • 动态渲染的受控性:airi 中部分 UI 库组件(如 shadcn-vue 系封装)通过 props 拼接类名,根配置 uno.config.ts 为此把 components|srcstage-uiui 目录纳入提取 include。要启用 compile-class 的组件必须保证其 class 是静态模板字符串,否则 keepOriginal 语义与运行时类都容易引起困惑;
  • 与 Safelist / 动态图标的关系transformerCompileClass 只做 HTML 文本改写,不参与 safelist 生成;airi 根配置里通过 safelist 预生成的主题色/图标类(见 uno.config.ts)不会受影响;
  • 多应用一致性:monorepo 中若 docsapps/*packages/* 各自维护 uno 配置,请让 triggerclassPrefix、ESLint prefix 三者在同一应用内保持一致,避免"规则要求前缀、转换器不识别前缀"的错位。

综上,transformerCompileClass 是 UnoCSS 中"小改动、大收益"的经典转换器:一行配置加入 transformers,在 HTML 模板上用 :uno: 前缀标记热点类组合,即可系统性压缩 HTML 体积、屏蔽类名细节并降低解析开销。结合 airi 仓库根 uno.config.ts 中已有的 transformerVariantGroup / transformerDirectives 配置,它完全可以无缝追加进同一管线,是面向生产环境静态产物优化值得优先尝试的一步。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
899
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525