SuperAPI AI 工具集

component-reuse-first

前端与建站

查看项目

更新于 10-16 22:42

技能介绍

用途

Component Reuse First 是一套针对 UI 组件开发的编码规范,用于约束在创建界面组件时的行为:在动手写新组件之前,先穷尽式地检查现有组件是否已经覆盖需求,只有在复用确实不可能时才新建,并且新建时面向下一次复用进行设计。

核心工作流

1. 创建前必须搜索

在编写任何新组件之前,并行执行以下检查:

  • Glob 扫描常见组件目录:
    • **/components/**/*.{tsx,jsx,ts,js,vue,svelte}
    • **/ui/**/*.{tsx,jsx,vue,svelte}
    • **/shared/**/*.{tsx,jsx,vue,svelte}
    • **/design-system/**/*、**/lib/components/**/*
  • Grep 检索概念名与同义词:
    • 用户要 “Modal” → 检索 Modal|Dialog|Popup|Overlay|Sheet|Drawer
    • 用户要 “Button” → 检索 Button|Btn|IconButton|CTA
    • 用户要 “Card” → 检索 Card|Panel|Tile|Box
    • 用户要 “Input” → 检索 Input|TextField|TextInput|FormField
    • 用户要 “List” → 检索 List|Table|DataGrid|Items
  • 检查导入:查看相似页面或特性已经在使用什么
  • 检查 package.json:识别已存在的设计系统库(shadcn/ui、MUI、Chakra、Mantine、Ant、Radix、HeroUI、NextUI、Tamagui、native-base 等),优先使用它们而不是手写

2. 决策树

搜索之后:

  • 存在完全匹配 → 原样复用,不要重复实现。
  • 存在接近匹配(90% 以上) → 通过 props/变体扩展现有组件,不要分叉。
  • 存在部分匹配 → 将现有组件重构为基础组件加变体,或通过组合实现,避免复制粘贴。
  • 没有匹配 → 新建,并遵循下文的可复用默认规则。

在写代码前明确向用户说明决策,例如:“在 src/ui/Button.tsx 找到带 variant prop 的 Button —— 新增 ghost 变体”或“没有匹配的 modal —— 在 src/ui/Modal.tsx 新建 Modal”。

3. 新建时的可复用默认规则

当确实需要新建组件时,为下一个调用者而建,而非只为当前场景:

放置位置

  • 共享/通用 → components/ui/、src/ui/ 或项目的设计系统路径
  • 特性内专用(仅在某特性内有意义)→ features/<feature>/components/
  • 绝不把可复用基础组件放进路由/页面文件

API 设计

  • 接受 className 并转发 ref(React:forwardRef + cn(className) 模式)
  • 将剩余 props 展开到底层元素(...props / v-bind="$attrs")
  • 使用变体(如 cva、tv、prop 联合类型)而不是复制组件
  • 使用 children/slot 而非硬编码内容
  • 使用语义化 prop 名称(variant、size、tone、intent),而非视觉化名称(bigBlueButton)
  • 必填与可选:最小化必填接口,其余提供合理默认值

组合优于配置

  • 优先使用复合组件(Card.Header、Card.Body)而非巨型 prop 集合
  • slot/children 模式优于大量 *Content prop

样式

  • 沿用项目既有方案(Tailwind、CSS modules、styled-components、vanilla-extract),不要引入新的样式系统
  • 使用设计令牌/主题值,不要硬编码颜色或间距

类型安全(TS 项目)

  • 扩展原生元素 props:ButtonHTMLAttributes<HTMLButtonElement>
  • 行为不同时使用可辨识联合定义变体(如 as="link" | "button")

无障碍

  • 默认使用正确的语义元素(button 对 div)
  • ARIA 属性通过 props 传递
  • 键盘交互在基础组件层处理

4. 创建之后

  • 若项目使用 barrel 文件,从目录的 index.ts 导出
  • 若项目有 Storybook/文档,补充进去
  • 如果搜索时发现多个现有组件可被新组件替代,告知用户(不要未经要求就重构)

需要拒绝的反模式

  • ❌ 在已有 Button 旁边创建 Button2、NewButton、CustomButton
  • ❌ 在页面内联定义明显可复用的组件
  • ❌ 复制粘贴组件只为改两行,而不是加一个 prop
  • ❌ 硬编码文案/颜色/尺寸导致无法复用
  • ❌ 已有 UI 库时再引入第二套设计系统
  • ❌ 以“组件很简单”为理由跳过搜索步骤

快速判断法则

  • 如果你打下 function Button( 而仓库里已有 Button → 停下,复用。
  • 如果新组件没有任何 props → 它大概率不可复用,询问是否应接受内容/变体。
  • 如果你即将写下 20 分钟前在另一个文件见过的相同 JSX → 抽取出来。

示例交互

用户: “给删除操作加一个确认弹窗。” 预期: 检索 Modal|Dialog|Confirm,在 src/ui/ConfirmDialog.tsx 找到 ConfirmDialog → 复用,传入 title、onConfirm、destructive。

用户: “创建一个定价卡片组件。” 预期: 检索 Card,在 src/ui/Card.tsx 找到 Card 基础组件 → 用 Card + Card.Header + Card.Body 组合出 PricingCard,放在 features/pricing/components/,不要重新造卡片框架。

用户: “我需要一个带加载旋转器的按钮。” 预期: 检索 Button,找到的按钮没有 loading prop → 给现有 Button 加 loading?: boolean,不要创建 LoadingButton。

激活触发条件

当对话涉及以下内容时该技能应激活:

  • 创建、构建、搭建或添加 UI 组件
  • 关键词:component、button、modal、dialog、card、form、input、table、list、dropdown、menu、sidebar、header、footer、layout、page、view、screen、widget
  • 框架:React、Vue、Svelte、Angular、Solid、SwiftUI、Jetpack Compose、Flutter
  • 短语:“make a”、“build a”、“I need a”、“create a”、“add a” + UI 名词