news 2026/9/26 6:28:46

Kumo 自定义 Lint 规则揭秘:设计系统如何用 5 条规则从源头锁住团队代码一致性

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kumo 自定义 Lint 规则揭秘:设计系统如何用 5 条规则从源头锁住团队代码一致性

Kumo 自定义 Lint 规则揭秘:设计系统如何用 5 条规则从源头锁住团队代码一致性

【免费下载链接】kumoCloudflare's component library for building modern web applications.项目地址: https://gitcode.com/gh_mirrors/kumo5/kumo

Kumo 是 Cloudflare 开源的 React 组件库(设计系统)。它的做法不是靠 Code Review 口头约定,而是用5 条自定义 Lint 规则从源头强制颜色令牌、暗色模式、组件规范、包边界与组件契约——所有"设计系统违规"都在你写代码的那一刻被机器拦截。这篇文章带你拆解这 5 条 Kumo 自定义 Lint 规则各自解决什么问题,以及如何借鉴到你的团队。

为什么设计系统需要自定义 Lint 规则?

组件库中,"视觉一致"是硬要求。但人工审查很难兜住这些情况:

  • 有人图省事,直接写原生颜色类,绕过设计令牌;
  • 有人手动用dark:前缀切换暗色模式,导致暗色表现不一致;
  • 新组件不遵循团队约定的变体(variant)命名与导出结构;
  • Monorepo 里用../../相对路径"偷渡"到兄弟包内部实现;
  • 已废弃的 prop 被新代码重新使用。

通用解法就是自定义 Lint 规则:把规则写成插件,挂到 Lint 检查器上(Kumo 用的是基于 Rust、速度更快的 Oxlint),让机器在每次检查时自动报告违规。入口文件 lint/kumo-plugin.js 一次性注册了 5 条规则:

规则名拦截什么
no-primitive-colorsTailwind 原生色(如bg-blue-500)
no-tailwind-dark-variant手动用dark:类切换颜色
enforce-variant-standard组件变体导出不符合命名规范
no-cross-package-imports相对路径跨包导入
no-flow-node-custom-renderFlow 自定义节点未透传 props 和 ref

规则一:no-primitive-colors——封杀"裸颜色",强制设计令牌

这是逻辑最重的一条,位于 lint/no-primitive-colors.js。

问题:如果每个组件都写bg-blue-500、border-red-500,主题一换品牌色就全乱了。

做法:

  1. 规则启动时直接读取两份主题 CSS 文件(theme-kumo.css与theme-fedramp.css,位于 packages/kumo/src/styles/),解析出所有--color-*与--text-color-*自定义属性,构成"合法令牌白名单"——白名单与主题文件天然保持同步,改主题不用改规则;
  2. 遍历 JSX 中所有类名字符串(模板串、字符串拼接、三元表达式都能被递归提取出来),一旦发现bg-、text-、border-、ring-等颜色前缀:
    • 命中 Tailwind 原生色系(red、blue、slate 等 21 个色族)→ 报no-primitive-colors,提示改用 Kumo 语义令牌;
    • 命中"未知令牌"(比如语义色拼错)→ 报invalid-color-token,错误信息里直接点出具体是哪个令牌没定义在主题文件里。

亮点:bg-white、text-black被刻意放行(它们是通用色);text-sm、bg-clip-padding这类"长得像颜色但其实不是颜色"的工具类,通过一张非颜色工具表加正则模式精准排除,避免误报。这种"白名单驱动"的写法,是设计令牌强制落地的好范本。

规则二:no-tailwind-dark-variant——封杀dark:,暗色模式统一收口

位于 lint/no-tailwind-dark-variant.js。规则一句话:任何className里的dark:bg-...、dark:text-...都不允许。

问题:设计系统的暗色模式应该由主题令牌统一处理(换主题即自动换色),而不是每个页面自己写dark:变体,否则会出现"双重暗色"或暗色表现不一致。

实现细节:

  • 正则要求dark:后面必须跟着合法的工具名(如dark:bg-blue-500),这样就不会误报{ dark: "vesper" }这种普通对象键;
  • extractStrings函数能递归收集字面量、模板字符串、字符串拼接、数组、对象、函数参数、三元表达式、甚至 JSX 文本中的类名片段——想用动态字符串绕过都行不通;
  • JSX 的className/class属性被专门监听,其余代码位置同样扫描。

报错信息直接给出改法:"请使用设计系统令牌或组件 API 处理暗色模式"。

规则三:enforce-variant-standard——变体导出必须符合命名契约

位于 lint/enforce-variant-standard.js。

背景:Kumo 的组件采用"机器可读"的变体体系——每个组件必须导出KUMO_{组件名}_VARIANTS(变体定义)与KUMO_{组件名}_DEFAULT_VARIANTS(默认值),文档站、AI 组件注册表、代码生成都依赖这份结构。

规则做什么:

  • 只对src/components/{name}/{name}.tsx这类组件文件生效,组件名直接由文件路径解析(连字符自动转下划线);
  • 逐个检查导出名是否与KUMO_{COMPONENT}_VARIANTS、KUMO_{COMPONENT}_DEFAULT_VARIANTS、可选的KUMO_{COMPONENT}_BASE_STYLES完全一致;
  • 命名写错时,报错会同时给出你写的名字和应该写的名字;文件末尾若缺少必需导出,还会列出你实际导出了哪些变体相关符号。

这类"把命名约定当契约"的规则,把团队文档里的承诺变成了机器硬校验。

规则四:no-cross-package-imports——封杀相对路径"爬出包"

位于 lint/no-cross-package-imports.js。

问题:Monorepo 里写import x from "../../kumo/src/button"很方便,但它绕过了包的公开 API,目录一重构就全线报错。

判定逻辑:

  • 正则匹配"若干层../+ 已知包目录名(kumo / kumo-docs-astro / kumo-figma)";
  • 要求至少向上两级(../../):只向上一级(../kumo/)大概率是同包内恰好同名的本地目录,不报——这个细节巧妙避免了误报;
  • 静态import、动态import()、require()、export from、export * from五种入口全覆盖。

错误信息直接给出替代方案:改用包名(如@cloudflare/kumo)导入。

规则五:no-flow-node-custom-render——用静态分析检查"组件契约"

位于 lint/no-flow-node-custom-render.js,是最"硬核"的一条。

问题:Flow 组件的<Flow.Node render={...}>里放入自定义节点组件时,该组件必须把收到的props展开透传、把ref转发给根元素,否则节点无法聚焦、拖拽和测量,整个流程图行为会异常。靠人肉检查几乎不可能覆盖所有组合。

规则做法(一次小型静态数据流分析):

  1. 收集文件里的组件候选:命名函数组件、const X = (props) => ...、forwardRef包裹的函数(支持重命名导入);
  2. 逐个分析组件渲染体:是否出现了 props 展开、是否把 ref 绑定到了元素上;
  3. 找出所有出现在<Flow.Node>的render属性里的自定义组件;
  4. 文件结束时对照结论:缺 ref 报missingRef,缺 props 报missingProps,都缺则合并报告。

为应对真实代码,规则还处理了 TypeScript 断言(as、satisfies、!)解包、forwardRef重命名导入、A.B形式的 JSX 成员表达式、ref与属性访问的区分等边界情况——这是一条"真正理解 React"的 Lint 规则。

彩蛋:第 6 条只存在于包内的规则

packages/kumo/lint/no-deprecated-props.js 从自动生成的 AI 组件注册表(ai/component-registry.json)里读取废弃信息,谁用了废弃 prop(例如Select的hideLabel、Banner的text)就报错,消息里直接附上替代方案。

这展示了一个很妙的模式:规则的数据源来自生成物——prop 在注册表里标记 deprecated,Lint 规则自动获得,无需手工维护任何清单,"文档"与"执行"就是同一份数据。

规则如何接线:两层配置

  • 仓库根目录vite.config.ts:把packages/kumo/lint/kumo-plugin.js作为 jsPlugin 加载,4 条通用规则(no-cross-package-imports、no-primitive-colors、no-tailwind-dark-variant、no-flow-node-custom-render)全部设为"error"——Lint 不过,提交就过不去;
  • 包内packages/kumo/vite.config.ts:把enforce-variant-standard也设为"error",这条规则只在组件源码目录生效,所以放在包里;
  • 每条规则都配有测试文件(如 enforce-variant-standard.test.ts),保证规则本身不漂移。

这种"根目录管通用规则、包内补充专属规则"的分层,是 monorepo 的通用好模式。

可借鉴到你的团队的清单

  1. 白名单优于黑名单:令牌表直接从主题源文件解析(参考no-primitive-colors),规则与设计系统自动同步;
  2. 报错信息写出改法:给出正确的导出名、包名、替代 prop,而不只是"这里错了";
  3. 误报工程化:非颜色工具类白名单表、../层级 ≥ 2 的判定、dark:正则边界——好规则的价值一半在防误报的细节里;
  4. 规则读元数据:废弃标记、变体定义等由构建期生成,Lint 规则运行时读取,文档即规则;
  5. 规则要有测试:每条规则配一个.test.ts,防止规则自身回归;
  6. 设为 error 级别:能挡住合并的 Lint 才真正生效。

总结

Kumo 对"如何让团队代码保持一致"的回答,不是写更多文档,而是5 条自定义 Lint 规则 + 1 份注册表元数据:颜色令牌、暗色模式、变体命名、包边界、组件契约,全部在源头被机器强制。任何在做设计系统或组件库的团队,都可以直接抄这套"规则即规范"的作业。

【免费下载链接】kumoCloudflare's component library for building modern web applications.项目地址: https://gitcode.com/gh_mirrors/kumo5/kumo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 6:26:33

Agent记忆与知识库搭建:从文件到RAG与知识编译实战

做 Agent 开发的人&#xff0c;迟早会在同一堵墙上撞一次&#xff1a;模型的上下文窗口撑爆&#xff0c;追问不到历史信息&#xff0c;回答开始靠猜。我早期做过一个客服类 Agent&#xff0c;对话超过三轮之后&#xff0c;它就开始忘记用户刚说过的需求&#xff0c;更别提调用之…

作者头像 李华
网站建设 2026/9/26 6:26:30

aarch64架构服务器安装 Miniconda

Miniconda aarch64 安装笔记目标&#xff1a;ARM aarch64服务器&#xff0c;安装到指定目录下&#xff0c;以 ~/公共/vscode/test/miniconda为例&#xff0c;不修改.bashrc&#xff0c;不影响服务器其他环境1. 创建目录mkdir -p ~/公共/vscode/test/miniconda mkdir -p ~/公共/…

作者头像 李华
网站建设 2026/9/26 6:26:25

Agent接入数据库的正确姿势:工具封装、连接池与安全架构全解析

做Agent接入数据库这件事&#xff0c;我前后折腾了快两年。最早抱着“给大模型一个MySQL连接串&#xff0c;让它自己查”的想法&#xff0c;结果被现实狠狠教育&#xff1a;幻觉SQL、连接池被打爆、权限裸奔、事务悬挂&#xff0c;每个坑都踩了个遍。后来我逐渐总结出一套相对稳…

作者头像 李华
网站建设 2026/9/26 6:26:00

回归项目实战指南:从数据准备、模型选型到部署落地的完整链路

回归项目实战&#xff0c;这六个字看起来平淡&#xff0c;实际上做起来千头万绪。我接手过不少预测类项目&#xff0c;从工业参数预测到销量预估&#xff0c;再到金融风控里的额度测算&#xff0c;本质上都是回归问题。但回归这件事&#xff0c;最容易踩的坑不是“模型跑不出来…

作者头像 李华
网站建设 2026/9/26 6:24:57

SpringBoot+Vue社区维修平台:接单并发与状态同步实战

简介&#xff1a;本资源为基于SpringBoot与Vue的社区维修平台毕业设计完整项目&#xff0c;面向计算机相关专业需要完成课程设计、毕业设计或期末大作业的学生。项目采用前后端分离架构&#xff0c;后端以SpringBoot&#xff08;或SSM&#xff09;搭建&#xff0c;数据库使用My…

作者头像 李华