- 前端
- 构建工具
【免费下载链接】unocss
The instant on-demand atomic CSS engine.
UnoCSS 为工程化质量保障提供了官方 ESLint 集成:@unocss/eslint-plugin(推荐通过@unocss/eslint-config引入)。本文以仓库内 docs/integrations/eslint.md 与 packages-integrations/eslint-plugin/README.md 为核心骨架,结合packages-integrations/eslint-plugin的源码与测试,完整讲解插件的安装、Flat Config /.eslintrc两种接入方式、order、order-attributify、blocklist、enforce-class-compile四条规则的语义与全部可选参数,并深入其底层工作原理。读完你可以在任何 Vue / React / Svelte 项目中落地 UnoCSS 的类名排序与禁用规则检查,并理解规则如何直接复用 UnoCSS 引擎的真实生成器做判断。
一、为什么需要 UnoCSS 的 ESLint 插件
UnoCSS 按需生成原子化 CSS,一个元素的样式由class属性中的一串工具类名决定。随着类名增多,两个工程问题随之而来:
- 顺序不一致:同一个类名集合,在不同文件里书写顺序不同,生成的 CSS 规则顺序也不同(影响层叠结果),代码评审时也容易反复争论。
- 禁用类名无法拦截:项目里想淘汰
bg-red-500、border等工具类,或在多套设计系统之间禁用某类命名,纯靠人肉 review 难以覆盖全局。
官方 ESLint 插件把这些问题交给静态检查与自动修复解决。它的核心亮点在于:规则不是靠硬编码的正则匹配,而是真正加载你的uno.config.ts,调用 UnoCSS 引擎对类名进行解析、排序与拦截判断,因此结果与运行时构建完全一致。这一点从 worker.ts 中可以看到:它通过loadConfig读取配置并用createGenerator构造真实的 UnoCSS 生成器,规则侧再通过synckit的createSyncFn同步调用 worker(见 _.ts)。
二、安装
插件本体为@unocss/eslint-plugin,推荐直接安装封装好的@unocss/eslint-config(它内部依赖并导出了插件,见 eslint-config/src/index.ts 与 eslint-config/src/flat.ts):
pnpm add -D @unocss/eslint-configyarn add -D @unocss/eslint-confignpm install -D @unocss/eslint-configbun add -D @unocss/eslint-config前提条件:规则运行需要读取 UnoCSS 配置文件。如果项目根目录没有uno.config.ts,worker 会抛出错误提示先创建配置文件(见 worker.ts 中的报错逻辑)。
三、两种 ESLint 配置风格的接入
3.1 Flat Config 风格(ESLint 9+ 默认)
在eslint.config.js中引入 flat 配置:
import unocss from '@unocss/eslint-config/flat' export default [ unocss, // other configs ]@unocss/eslint-config/flat子路径导出的是插件预置的 flat 配置对象。从源码 configs/flat.ts 可以看到,它注册了unocss插件命名空间,并默认开启两条 warn 级规则:
const flatConfig = { plugins: { unocss: plugin }, rules: { 'unocss/order': 'warn', 'unocss/order-attributify': 'warn', }, }3.2 传统.eslintrc风格
{ "extends": [ "@unocss" ] }对应 legacy 推荐配置见 configs/recommended.ts,注册@unocss插件并同样只默认开启order与order-attributify两条 warn 规则。
两个配置对象通过 index.ts 统一挂在
configs.recommended与configs.flat上,这也是unocss.configs.flat这种写法的来源。
四、规则总览
规则名前缀取决于配置风格:
- Flat config:
unocss/<rule-name> - Legacy
.eslintrc:@unocss/<rule-name>
可用的规则(注册于 plugin.ts):
| 规则名 | 作用 | 默认开启 |
|---|---|---|
order | 强制class属性中工具类按特定顺序排列 | 是(warn) |
order-attributify | 强制 attributify 属性按特定顺序排列 | 是(warn) |
blocklist | 禁用配置blocklist中指定的类名 | 否 |
enforce-class-compile | 强制类名使用:uno:编译前缀 | 否 |
特别说明:order-attributify只排序 attributify属性本身,不会对属性值内部的工具类排序,例如un-before="text-center font-sans color-gray"中的内容不会被重排——这种值内部的排序仍由order负责。
五、order:类选择器排序规则
5.1 基本行为
order检查class/className属性(源码 constants.ts 中的CLASS_FIELDS = ['class', 'classname']),对字符串中的工具类调用 UnoCSS 引擎重新排序,乱序时报UnoCSS utilities are not ordered并自动修复(fixable: 'code')。
它覆盖的语法形式非常广(见 order.ts 与 order.test.ts):
- JSX/TSX:
className="mx1 m1 mr-1"、className={"..."}、模板字符串className={...}、String.raw、带插值的模板字符串(只重排纯文本片段)。 - Vue 模板:
class字面量与:class绑定中的字符串字面量。 - Svelte:
class="..."及其{test ? 'a' : 'b'}三元表达式。 - 函数调用:
clsx(...)、classnames(...)以及你通过选项指定的任意工具函数(支持字符串、模板字符串、条件表达式、逻辑表达式、对象键值、数组嵌套、cva/tv变体对象等)。 - 变量声明:变量名匹配的字符串字面量、对象字面量(含嵌套、
as const satisfies类型断言,见order-unoVariables-satisfies测试组)。
一个 Vue 模板示例:
<!-- 修改前 --> <div class="mx1 m1 mr-1"></div> <!-- 修改后(自动修复) --> <div class="m1 mx1 mr-1"></div>Svelte 中的示例(见 order.test.ts):
<!-- 修改前 --> <div class="mr-1 ml-1"></div> <!-- 修改后 --> <div class="ml-1 mr-1"></div>5.2 排序原理:复用引擎而非硬编码
order之所以"懂"UnoCSS 的排序规则,是因为它调用了共享的排序实现 sort-rules.ts。该实现的关键步骤:
- 先用
parseVariantGroup展开变体组,再用splitVariantGroupBody切分每个工具类; - 逐个调用
uno.parseToken(i)让引擎真正解析工具类,解析不出的视为未知类名,保持原位不动(只排序已知类名); - 用解析结果中的规则序号
token[0][0]加上变体层数权重variantHandlers.length * 100_000计算排序键,同序号时按字典序比较; - 排序后重新用
collapseVariantGroup收起变体组,最后把未知类名拼回头部。
这也解释了为什么order要求项目存在uno.config.ts:排序顺序完全由你的 preset(如presetWind3)与自定义规则决定。
5.3order规则选项
order接收一个可选的 options 对象(schema 见 order.ts):
unoFunctions(string[]):标记哪些函数调用需要检查。这些是普通函数名而非模式,匹配时忽略大小写。默认['clsx', 'classnames']。unoVariables(string[]):标记哪些变量声明需要检查。这些是带i标志的正则模式。默认['^cls', 'classNames?$'],例如会匹配变量名clsButton与buttonClassNames。
自定义示例:
export default [ unocss, { rules: { 'unocss/order': ['warn', { unoFunctions: ['clsx', 'classnames', 'cva', 'tv'], // 检查这些工具函数的入参 unoVariables: ['^cls', 'classNames?$', '^theme'], // 匹配 themeDashboard 等变量 }], }, }, ]对应测试见 order.test.ts 中的order-unoFunctions(含cva({ variants: { size: { small: 'px-2 text-sm py-1' } } })这类变体对象的重排)与order-unoVariables两组用例。
六、order-attributify:attributify 属性排序规则
如果你启用了 preset-attributify,HTML 元素会写成这样:
<div text-center font-sans color-gray un-before="text-center font-sans color-gray" />order-attributify专门对这些无值的 attributify 属性(如text-center、font-sans)按 UnoCSS 排序规则重排。从 order-attributify.ts 的源码可以看到:
- 它只处理 Vue 模板的
VStartTag,过滤出所有无值属性(排除style、class、classname、value等原生属性,见IGNORE_ATTRIBUTES); - 把这些属性名拼成字符串交给
syncAction(..., 'sort', ...)排序; - 修复时用
magic-string删除乱序属性并在第一个属性位置重写(源码 order-attributify.ts)。
再次强调:它不处理属性值内部,un-before="text-center font-sans color-gray"的值内部乱序要交给order检查。
七、blocklist:禁用指定工具类(可选规则)
7.1 规则语义
blocklist不是默认开启的规则。启用后,当代码中出现 UnoCSS 配置blocklist中列出的工具类时,会抛出警告或错误。它既检查class字面量(Vueclass/:class、JSXclassName、Svelteclass),也检查attributify 无值属性名(见 blocklist.ts 的VStartTag分支)。
报错消息格式为"{{name}}" is in blocklist{{reason}},即默认展示被禁的类名;配置了自定义消息时追加: 你的消息。
7.2 启用方式
import unocss from '@unocss/eslint-config/flat' export default [ unocss, { rules: { 'unocss/blocklist': 'error', // 或 'warn' }, }, ]{ "extends": ["@unocss"], "rules": { "@unocss/blocklist": "error" } }仓库自带的 fixtures 就是这么用的(fixtures/eslint.config.ts)。
7.3 自定义拦截消息
你可以为被禁规则定制消息,让提示更有指导性。消息可以是静态字符串或接收类名返回字符串的函数(函数形式可结合原始类名动态生成建议):
export default defineConfig({ blocklist: [ ['bg-red-500', { message: 'Use bg-red-600 instead' }], [/-auto$/, { message: s => `Use ${s.replace(/-auto$/, '-a')} instead` }], // 例如 "my-auto" 被禁用时提示:Use "my-a" instead ], })注意这里同时用到了两种 blocklist 条目写法:'bg-red-500'字符串字面量,以及[匹配器, { message }]元组形式——元组中匹配器可以是正则、字符串或接收类名返回布尔值的函数,message的取值函数在 worker.ts 中按raw类名求值。测试 blocklist.test.ts 与规则目录下的 uno.config.ts 覆盖了静态消息、动态匹配、动态消息三类场景(例如h-auto被提示改为h-a)。
7.4 底层判定流程
blocklist的判定同样发生在 worker 中(worker.ts):先对类名字符串执行uno.applyExtractors提取工具类,再对每个提取结果依次做uno.getBlocked(raw)直接命中、config.preprocess预处理、matchVariants匹配变体后的间接命中三层检查,从而保证被禁类名即使带变体前缀(如hover:)也能被识别。
八、enforce-class-compile:强制类编译前缀(可选规则)
8.1 规则语义与修复能力
enforce-class-compile专为配合 compile class transformer 设计:当class属性或:class指令的内容不以:uno:开头时,报告prefix::uno:is missing,并且(默认)自动为所有 class 属性与指令补上:uno:前缀,把长串工具类编译为带哈希的短类名。
<!-- 修改前 --> <div class="mr-1"></div> <!-- 自动修复后 --> <div class=":uno: mr-1"></div>它覆盖 Vue 中的多种绑定形态(见 enforce-class-compile.test.ts 与 enforce-class-compile.ts):
class="mr-1"静态属性;:class="'mr-1'"字符串字面量;:class="condition ? ':uno: mr-1' : ':uno: ml-1'"三元表达式(修复两侧);:class="{'mr-1': condition}"对象字面量键名,以及{flex}简写属性(会展开为{':uno: flex': flex});:class="mr-1"模板字符串。
8.2 规则选项
prefix(string):编译前缀,必须与transformerCompileClass的触发词一致,用于配合自定义前缀。默认:uno:。enableFix(boolean):设为false时只报告不自动修复,适合渐进式迁移(先把存量代码标红,再逐步手动接入)。默认true。
import unocss from '@unocss/eslint-config/flat' export default [ unocss, { rules: { 'unocss/enforce-class-compile': ['warn', { prefix: ':uno:', enableFix: true, // 迁移期可设为 false,仅报告 }], }, }, ]8.3 与 compile-class transformer 的配合前提
enforce-class-compile的prefix选项本质上对应transformerCompileClass的trigger参数——后者默认匹配:uno:(正则见 transformer-compile-class/src/index.ts),两者必须保持一致,否则 ESLint 补上的前缀在构建时不会被 transformer 识别。如果你自定义了 trigger(例如通过trigger正则或:uno-名称:命名编译类),请同步修改本规则的prefix。
兼容性注意:该规则目前只支持 Vue(源码中scriptVisitor对 JSX 与 Svelte 分支留了todo: add support | NEED HELP占位,见 enforce-class-compile.ts)。Svelte 场景建议改用svelte-scoped模式;若需要在 JSX 中使用,可向项目提交 PR 补全。
九、可选规则统一启用模板
以下两段模板供整体参考(来自官方文档),可按需把'warn'换成'error'或追加 options 数组:
import unocss from '@unocss/eslint-config/flat' export default [ unocss, { rules: { 'unocss/blocklist': 'warn', // 或 "error" 'unocss/enforce-class-compile': ['warn', { /* options */ }], }, }, ]{ "extends": ["@unocss"], "rules": { "@unocss/blocklist": "warn", "@unocss/enforce-class-compile": ["warn", { "prefix": ":uno:" }] } }十、底层工作原理:worker 线程 + 真实引擎
规则与 UnoCSS 引擎之间隔着一层精心设计的桥接,理解它有助于排查"规则和构建结果不一致"之类的问题:
- 规则侧(同步):_.ts 用
synckit的createSyncFn(join(distDir, 'worker.mjs'))把sort/blocklist动作同步派发到 worker(dist/worker.mjs由 worker.ts 通过runAsWorker注册)。 - Worker 侧(异步):worker.ts 用
loadConfig加载 UnoCSS 配置,createGenerator({ ...config, warn: false })构造生成器,并按缓存键(显式configPath、文件所在目录、process.cwd())缓存生成器实例。 - 多仓库(monorepo)支持:未显式指定
configPath时,worker 从被检查文件所在目录向上查找配置文件(getSearchCwd,见 worker.ts),因此每个子包可以使用自己的uno.config.ts。 - 处理器虚拟路径:markdown / MDX 等经 ESLint processor 生成的虚拟文件路径(形如
/path/to/source.ext/virtual_file.ext)会被剥离出真实目录再定位配置。
如果你需要强制规则使用某个特定配置文件(比如项目根与 lint 入口不一致时),可以在 ESLint 配置的settings中指定:
export default [ unocss, { settings: { unocss: { configPath: './uno.config.ts', // 显式指定配置文件 }, }, }, ]这个settings.unocss.configPath的类型声明定义在 types.ts,测试文件中也普遍使用它指向各自的uno.config.ts(如 order.test.ts)。
十一、运行与验证
在 fixtures 目录验证插件效果:
cd packages-integrations/eslint-plugin/fixtures && eslint ./srcfixtures 仓库提供了现成的验证素材:fixtures/src/App.vue、fixtures/src/app.tsx、fixtures/src/+page.svelte,配合 fixtures/eslint.config.ts(开启了unocss/blocklist: 'error')与 fixtures/uno.config.ts(配置了presetWind3、variant-group transformer 与 blocklist 匹配器)即可跑通完整链路。
也可以直接运行规则测试确认行为符合预期(测试均基于eslint-vitest-rule-tester,与真实 ESLint 运行时行为一致):
- order.test.ts:覆盖 Vue / JSX / Svelte 三端与
unoFunctions/unoVariables两个选项; - blocklist.test.ts:覆盖静态 / 动态 blocklist 与自定义消息;
- enforce-class-compile.test.ts:覆盖前缀补全、自定义 prefix、
enableFix: false只报不改等场景。
十二、最佳实践小结
- 最小起步:安装
@unocss/eslint-config,Flat 或.eslintrc二选一接入,即可获得order与order-attributify的 warn 级排序检查;确保项目根有uno.config.ts。 - 渐进开启可选规则:先以
warn启用blocklist与enforce-class-compile,配合enableFix: false完成存量迁移后再升级为error并开启自动修复。 - 统一工具函数名单:如果项目使用
cva、tv、superclass等组合类名工具,记得把它们加入order的unoFunctions,否则这些函数体内的类名不会被检查。 - prefix 保持一致:使用 compile-class 工作流时,
enforce-class-compile的prefix必须与transformerCompileClass的 trigger 完全一致。
结语
@unocss/eslint-plugin的价值在于把"类名排序、禁用拦截、编译前缀强制"这些与 UnoCSS 引擎强耦合的检查,做成了标准化的 ESLint 规则,并且直接复用真实的 UnoCSS 生成器,杜绝了 lint 结果与构建结果"两张皮"的问题。结合order/order-attributify的自动修复能力,它能让团队在原子化 CSS 的写法上保持高度一致,是 UnoCSS 生产级工程化中值得优先接入的一环。
- 前端
- 构建工具
【免费下载链接】unocss
The instant on-demand atomic CSS engine.
相关推荐
WebdriverIO ESLint 规则插件 eslint-plugin-wdio 完全指南:从安装配置到四类规则的源码级解析
WebdriverIO ESLint 规则插件 eslint plugin wdio 完全指南:从安装配置到四类规则的源码级解析 eslint plugin w
测试质量保障TanStack Query 官方 ESLint 插件:@tanstack/eslint-plugin-query 安装配置与 8 条规则源码级解析
TanStack Query 官方 ESLint 插件:@tanstack/eslint plugin query 安装配置与 8 条规则源码级解析 TanSt
前端缓存状态管理Gutenberg 官方 ESLint 插件 @wordpress/eslint-plugin 完全指南:配置预设、内置规则与 flat config 迁移实战
Gutenberg 官方 ESLint 插件 @wordpress/eslint plugin 完全指南:配置预设、内置规则与 flat config 迁移实战
后端前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考