☰
@shadcn/lint六大核心规则一次讲透:从no-restyle到no-unknown-classes全解析
2026/10/1 8:40:38 网站建设 项目流程

@shadcn/lint六大核心规则一次讲透:从no-restyle到no-unknown-classes全解析

【免费下载链接】lintAn agent-first linter for Tailwind design systems. Write design system rules that agents can verify.项目地址: https://gitcode.com/gh_mirrors/lint3/lint

@shadcn/lint 是一个面向 Tailwind 设计系统的 Lint 工具,它帮你把"哪些样式能改、哪些颜色能用"变成机器可检查的规则。当 AI 编码代理或团队成员写错样式时,它不仅能报错,还会告诉你该用哪个变体、哪个主题色来替代——这正是它被称为 "agent-first linter" 的原因。本文用一篇带你吃透它的6 大核心规则。

一、为什么需要 @shadcn/lint?🎯

用 TypeScript 类型也能限制style属性,但类型报错只说"不行",不说"该怎么做"。而 @shadcn/lint 的报错自带基于你组件库的修复建议:列出可用的 size、variant、主题色 token 和定义它们的文件路径。

它的核心特点:

  • ✅不改组件 API:规则写在 Lint 配置里,组件代码保持灵活
  • ✅无需 shadcn/ui:自己的 Tailwind 组件和主题就能用
  • ✅多框架支持:React、Vue、Svelte,ESLint 和 Oxlint 双引擎
  • ✅官方实测:在 150+ 次任务跑测中,AI 代理基本一轮纠错即可清零违规,成本降低 10%~48%

二、六大规则速览 📋

规则拦截什么一句话定位
no-restyle通过className重设计系统组件外观归组件,布局归页面
no-raw-colorsbg-pink-500等裸色板色、未声明 token、SVG 硬编码色颜色必须走主题
no-arbitrary-valuesp-[13px]、bg-[#333]等任意值值必须落在标尺上
no-inline-stylesstyle内联属性、<style>元素样式必须走 class
no-unknown-classesrounded-huge等 Tailwind 生成不了 CSS 的类名拼写和存在性兜底
require-static-classes`bg-${color}`这类 linter 读不懂的类名保证其他规则"看得见"

每条规则的完整文档都在 docs/rules/ 目录下,规则共享的allow/deny/contracts/message选项说明见 docs/rules.md。

三、no-restyle:设计系统组件的"外观锁" 🔒

这是最核心的一条规则。设计原则是:外观用组件变体,布局才交给className。

它怎么工作?规则把你的类名分成 8 个类别:layout(布局)、color(颜色)、typography(排版)、spacing(间距)、shape(形状)、effects(特效)、motion(动效)和unclassified(无法识别)。以allow: ["layout"]为例,mt-4、w-full放行,而p-4、bg-pink-500、rounded-full全部报错——且报错会列出组件的 sizes 和 variants。

三个进阶玩法:

  1. Contracts(契约):给不同组件定不同规则,比如允许CardTitle改排版、允许CardContent改间距,颜色谁都不能动
  2. deny 精准排除:布局整体放行但单独禁掉w-*
  3. 自定义文案:报错信息可写成 "Use a Button size: sm, lg",直接告诉代理该用什么

它能穿透 import、re-export 和转发className的包装组件,所以<SaveButton className="p-4">一样会被识别为对 Button 的重设计。

📄 详见:docs/rules/no-restyle.md

四、no-raw-colors:颜色只认主题 🎨

这条规则拦截三类"野生颜色":

  • 色板裸色:bg-pink-500、text-amber-500
  • 未声明 token:主题里没有highlight,写bg-highlight照样报错
  • SVG 硬编码色:fill="#ec4899"、stroke="red"这类字面量

报错时会列出主题已声明的 token、给出附近颜色的建议,并指明主题文件在哪。white、black、transparent、currentColor这类通用名直接放行。

新手常见的疑问:为什么@utility tap-target自定义工具类不报错?因为它属于你自己的词表;而.text-danger { color: #f00 }这种普通选择器不会被当 token,背后的颜色仍是裸色,照样会被抓。

📄 详见:docs/rules/no-raw-colors.md

五、no-arbitrary-values:值必须落在标尺上 📏

p-[13px]、rounded-[10px]、bg-[#333]是设计系统的大敌——它们绕过了你的 spacing 标尺和色彩 token。

这条规则的亮点是能给出精确替代:默认--spacing为 4px 时,p-[13px]会提示Use "p-3.25" instead (same value, on the scale),而且变体、负值、important 标记都会保留。

注意两个边界:

  • data-[state=open]:flex、bg-(--brand)这类任意变体和变量简写不算任意值,直接放行
  • 布局类任意值可用allow: ["layout"]放行,比如侧边栏的w-[320px]往往是合理的

📄 详见:docs/rules/no-arbitrary-values.md

六、no-inline-styles:样式请走 class 通道 🚫

组件里写style={{ color: "red" }}或塞一个<style>元素,都会让设计系统形同虚设。这条规则的检查相当细腻:

  • ✅放行:用 CSS 自定义属性传递动态值(style={{ "--panel-width": \${width}px` }}`)是官方推荐姿势
  • ❌报错:普通内联属性、自定义属性里的硬编码色值("--label-color": "#ec4899")、读不懂的 style 对象、<style>元素
  • 🔍会顺藤摸瓜:同文件的const colors = { accent: "#ec4899" }再引用colors.accent,一样会被查出来

例外按CSS 属性名配置(如动画库的transform),注意它不接收 Tailwind 类名。

📄 详见:docs/rules/no-inline-styles.md

七、no-unknown-classes:拼写错误的最后防线 🔍

rounded-huge、flex-cols、hovr:flex——这些类名 Tailwind 根本生成不了 CSS,页面"看起来能跑"其实没生效。这条规则直接调用你项目里安装的 Tailwind v4 + 主题 + 自定义工具类 + 插件来做存在性校验:

  • 拼写接近时给出纠错建议:flex-cols→ "Did you mean 'flex-col'?",编辑器里可一键替换
  • 主题里的@utility自定义工具和 CSS 类选择器都被识别,不误报
  • 外部样式表提供的类(如editor-root)通过allow加白名单

官方建议先从warn级别启用,边加白名单边收严。

📄 详见:docs/rules/no-unknown-classes.md

八、require-static-classes:让其他规则"看得见" 👀

前五条规则都有一个前提:类名要可读。如果你写了className={`bg-${color}`},linter 根本无法检查,等于规则失效。这条规则专门拦截"读不懂的类名":

  • ✅ 放行:静态字符串、完整类名间的三元选择、cn("mt-4", wide && "w-full")
  • ❌ 报错:模板拼接、导入的未知变量、未知函数调用

它是整个体系的"地基":读不懂的类名交给它报,读懂的部分继续由其他规则把关。官方建议在组件目录内关闭它(组件自己调用 variant 函数属于正常写法)。

📄 详见:docs/rules/require-static-classes.md

九、六条规则如何协同作战 🤝

单独使用当然可以,但组合起来才是完整防线:

场景谁负责
<Button className="p-4">不该改间距no-restyle
<Button className="p-[13px]">值不在标尺上no-arbitrary-values
<Button className="bg-pink-500">用了裸色no-raw-colors
<div className="flex-cols">类名不存在no-unknown-classes
style={{ color: "red" }}内联样式no-inline-styles
`bg-${color}`读不懂require-static-classes

⚠️ 两条容易踩的联动细节:

  1. 白名单互不通用:某条规则的allow只对它自己生效,no-restyle放行p-*不会放过no-arbitrary-values对p-[13px]的检查
  2. 组件目录记得关规则:no-restyle、no-arbitrary-values、require-static-classes要在组件目录内关闭,否则组件自己给自己定样式也会报错;而颜色类和存在性规则建议在组件目录保持开启

完整的渐进式接入路径(先 warn 后 error、逐条加规则)见 docs/adoption.md,规则背后的工作原理见 docs/how-it-works.md。

十、新手快速上手路径 🚀

  1. 装包:Node.js 20.19+,npm install -D @shadcn/lint eslint @typescript-eslint/parser(Oxlint 用户装oxlint即可)
  2. 配最小规则集:先开no-arbitrary-values,熟悉后再逐条加,完整步骤见 SETUP.md
  3. 让 AI 代理跑 lint:在AGENTS.md里加一句"改动后运行npm run lint并修复所有错误",规则的价值立刻翻倍
  4. shadcn/ui 项目零配置:components.json会自动发现组件目录和主题;自建组件用settings.shadcn指定ui前缀即可

规则的具体实现代码在 packages/lint/src/rules/ 下,每条规则一个文件,想深挖某个规则的边界行为,读源码 + 对应测试是最高效的方式。


一句话总结:no-restyle管"能不能改",no-raw-colors和no-arbitrary-values管"值对不对",no-unknown-classes和no-inline-styles管"写没写对",require-static-classes管"看不看得见"。六条规则各司其职,你的设计系统从此有了机器可执行的契约。

【免费下载链接】lintAn agent-first linter for Tailwind design systems. Write design system rules that agents can verify.项目地址: https://gitcode.com/gh_mirrors/lint3/lint

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询