🧩 组件库死亡倒计时—— AI 猖码冲击䞋的前端基础讟斜重构

1 阅读9分钟

🔍 匕子䞀䞪信号

最近我圚䞀䞪匀源项目里甚 Cursor 蟅助匀发 UI发现䞀䞪现象AI 几乎总是銖掚 Shadcn/ui。

需芁衚栌 → Shadcn Table + TanStack 需芁匹窗 → 盎接给䜠 Dialog 源码 需芁日期选择 → 组合 Popover + Calendar

即䜿我没指定它也借向甚 Shadcn 的源语来回答。

起初我有些抗拒。公叞项目里 Element Plus 的庞倧 API 早已是肌肉记忆。䜆有䞀次让 AI 给衚栌加行内猖蟑䞀次䜓验圻底改变了我对"组件库"这件事的讀知。


✹ 第䞀次惊讶AI 突然变准了

场景Element PlusShadcn/ui
AI 怎么改组件对着黑盒硬猜盎接修改源码文件
幻觉情况猖造䞍存圚的方法editRow()、@row-dblclick粟准插入状态切换逻蟑
类型掚富混甚 onMounted / onUpdated参数类型完党正确
根本原因AI 只看到 API 倖壳AI 看到党郚源码和状态流蜬

结论对 AI 来诎源码是䞀等公民API 文档只是二手信息。


🌪 第二次惊讶样匏匀始挂移

几呚后回顟敎䞪项目发现 UI 风栌圚悄悄分裂

样匏属性匀始前几呚后
圆角系统统䞀 8px8px、4px、盎角随机组合
卡片内蟹距统䞀 p-6p-4、p-5、p-6 亀错出现

AI 每次郜盎接改 Tailwind 类名来满足琐碎需求——改按钮颜色、调匹窗宜床、加 4px 行高。

Shadcn 把样匏控制权完党亀了出来䜆没保留任䜕纊束的技栏。自由垊来了粟准修改的胜力也垊来了讟计系统的碎片化。


🎯 䞀䞪深层矛盟 + 八䞪隐藏问题

这䞀次经验暎露了圓前组件库范匏的深层矛盟

䌠统库甚黑盒换皳定性把 AI 挡圚闚倖Shadcn 甚癜盒换可修改性华牺牲了䞀臎性。

䜆问题䞍止于歀。把"组件库"这䞪物种攟到 AI 猖码的聚光灯䞋审视䌚发现曎倚倱效点——这些䞍是某䞪库的猺陷而是敎䞪品类讟计假讟的厩塌。


🥇 框架锁定同䞀件事N 套实现

现状问题
Reactantd、shadcn、mui各有 APIAI è®°æ··
Vueelement-plus、naive-ui跟 React 完党䞍通甚
Svelte莫瘠的生态自己造蜮子

同䞀种行䞺暡匏䞋拉菜单、匹窗、衚栌被重倍实现了 N 次每次绑定䞀䞪框架。AI 切换䞊䞋文时准确率急剧䞋降。


🥈 版本锁定版本是给人类的䞍是给 AI 的

Element Plus v1 → v2: 改了倚少 API没人记埗枅。
AI 的训练数据混合了 v1 和 v2 的知识。
䜠的项目装了 v2。
AI 写的代码可胜调的是 v1 的 API。

版本号把"规范的挔进"和"实现的变曎"绑圚䞀起AI 无法区分。


🥉 平台绑定Web 䌚了移劚端从倎孊

行䞺䞋拉选择实现方匏
Webdiv + 绝对定䜍 + 滚劚列衚
移劚端原生 Picker / Bottom Sheet
CLIstdin/stdout 选项列衚

同䞀亀互语义䞉种实现䞉套组件库。AI 芁跚平台先孊䞉套 API。


📱 讟倇䞍感知

桌面端卡片有 hover觊屏䞍需芁。桌面端衚栌展瀺 20 列移劚端只胜展瀺 3 列。

组件䞍䌚告诉 AI"我圚手机䞊应该长什么样"。AI 只胜猜——桌面端对了移劚端倧抂率错。


📋 行䞺规范猺䜍

组件库暎露的是代码export function Select(props)。

䞍是行䞺规范"按 ArrowDown 高亮䞋䞀䞪选项按 Enter 选䞭按 Escape 关闭。"

AI 胜读代码䜆它芁的是讟计意囟——代码是"怎么做"AI 需芁"做什么"和"䞺什么"。


🔍 隐匏讟计决策

倌䞺什么圚哪记圕的
padding: 8px讟计评审决定的某人的脑子里
color: #2563eb品牌色 v3Figma 泚释里
radius: 4px vs 8px等级区分PR review 里

代码本身䞍携垊"䞺什么"。AI 修改时只胜倖郚掚断掚断错了就匕入䞍䞀臎。


📄 文档和测试的重倍劳劚

䞀䞪组件

写代码 + 写文档 + 写 Storybook + 写测试 = 4 仜犻散工䜜

必须保持同步——䜆现实䞭从来䞍同步。劂果 AI 已经生成了代码它就具倇了生成文档和测试所需的所有信息䜆没人让它做。


♿ 无障碍是附加品䞍是内建属性

每䞪组件库自己实现䞀次 ARIA。每䞪团队䞊线前再补䞀遍。AI 生成组件时无障碍是最后才被想起的事。

劂果规范本身就定义了"这䞪组件的 ARIA 角色是 menu"AI 䞀匀始就胜做对。


📊 党貌对比总结

绎床圓前组件库AI 需芁什么
框架绑定䞀䞪切换重孊行䞺独立于框架生成时适配
版本版本号捆绑䞀切版本绑定规范䞍绑定实现
平台Web 䞓属䞀套规范倚平台生成
讟倇桌面假讟讟倇差匂星匏声明
行䞺代码即规范规范独立于代码
决策藏圚讚论里猖码䞺可远溯的纊束
文档/测试手劚绎技氞远滞后䞀次产出倚视囟自劚生成
无障碍事后修补规范内建生成时保证

💡 代码越䟿宜什么越莵

AI 猖码正圚让代码的蟹际成本趋近于零。

写埗快 ≠ 写埗奜。写埗快 = 写埗烂的速床也快。

圓代码䞍再是皀猺资源皀猺的䞜西变了

越来越䟿宜越来越莵
写䞀䞪组件定义"什么是对的"
倍制粘莎绎技䞀臎性
堆功胜守䜏纊束和蟹界
修 bug保证正确性
写文档保证文档跟代码䞀臎

🏗 䞀䞪可胜的架构规范 → 生成

基于以䞊诊断䞀䞪方向逐析浮现

把组件库从"代码包"重构䞺"规范描述噚 + 生成匕擎"

这䞍是"把组件拆成几层"那是圚旧框架里做䌘化而是重新定义组件库的亀付物。

挔进路线囟

䌠统组件库 ──→ 源码级组件库 ──→ 规范驱劚生成 ──→ 组件库消倱
    │               │               │               │
    │  npm install  │ 源码倍制      │ Spec 驱劚    │ 意囟驱劚
    │  黑盒         │  癜盒         │  纊束 AI     │  AI 足借区
    │  AI 猜 API   │  样匏挂移     │  规范=资产   │  䞍需芁纊束
    │               │               │               │
    Element Plus   Shadcn/ui      这䞪架构        未来

架构瀺意囟

┌──────────────────────────────────────────────────────────────────┐
│                      🧠 规范层Spec                           │
│              唯䞀需芁人工绎技和版本化的䞜西                       │
│                                                                  │
│  ┌─────────────┐  ┌──────────┐  ┌──────────┐  ┌─────────────┐  │
│  │ 行䞺规范     │  │ 样匏规范  │  │ 无障碍    │  │ 平台/讟倇   │  │
│  │ 状态定义     │  │ Token映射 │  │ ARIA角色  │  │ 适配规则    │  │
│  │ 事件流蜬     │  │ 纊束规则  │  │ 键盘亀互  │  │ 差匂声明    │  │
│  └─────────────┘  └──────────┘  └──────────┘  └─────────────┘  │
└─────────────────────────┬────────────────────────────────────────┘
                          │ 读取
┌─────────────────────────▌────────────────────────────────────────┐
│                      ⚙ 生成匕擎Generator                    │
│                    AI 的工䜜䞍是人的工䜜                        │
│                                                                  │
│  读取 Spec + 项目䞊䞋文                                           │
│       ↓                                                          │
│  ┌─────────────────────────────────────────────────────────┐     │
│  │  蟓出                                                  │     │
│  │  📄 组件代码.tsx / .vue / .svelte                   │     │
│  │  📝 类型定义                                             │     │
│  │  🧪 测试甚䟋                                             │     │
│  │  📖 文档 / Storybook                                    │     │
│  └─────────────────────────────────────────────────────────┘     │
│                                                                  │
│  切换平台/框架 = 换䞀䞪生成目标Spec 䞍变                        │
└─────────────────────────┬────────────────────────────────────────┘
                          │ 检查
┌─────────────────────────▌────────────────────────────────────────┐
│                      🛡 纊束层Guardrails                     │
│              确保 AI 的蟓出没有速越蟹界                           │
│                                                                  │
│  ✅ 样匏必须匕甚 token犁止硬猖码                               │
│  ✅ 无障碍芁求必须满足䞍通过䞍提亀                             │
│  ✅ 代码必须通过项目 lint / type check                          │
│  ✅ AI 䞍埗修改规范层文件                                        │
└──────────────────────────────────────────────────────────────────┘

这䞪架构解决了什么

问题❌ 旧暡匏✅ 新架构
框架锁定䞀䞪框架䞀套库Spec 䞍变生成匕擎适配目标框架
版本锁定升级库 = 党局风险只有规范有版本实现始终生成最新
平台绑定Web/移劚端/CLI 各䞉套䞀套 Spec䞉䞪生成目标
讟倇䞍感知组件䞍知道自己圚哪运行Spec 䞭定义讟倇差匂规则
行䞺规范猺䜍代码里没有行䞺声明Spec 第䞀层就是行䞺定义
隐匏讟计决策藏圚评审讚论里Spec 明确记圕讟计纊束
文档测试重倍四仜犻散工䜜各自同步䞀次生成四䞪蟓出视囟
无障碍附加品䞊线前补Spec 内建生成时自劚包含

📝 䌪代码规范 vs. 实现

以䞋展瀺"规范"和"生成"之闎的关系——这䞍再是䌠统组件库的样子。

这是"组件库"——䞀䞪规范文件䞍是代码

// 文件䜍眮@specs/dropdown-menu.ts
// 匀发者绎技歀文件AI 䞍可修改

export const dropdownMenuSpec = {
  id: 'dropdown-menu',
  version: '2.1',

  // ── 行䞺规范 ──
  states: {
    isOpen: { type: 'boolean', default: false },
    activeIndex: { type: 'number', default: -1 },
    selectedValue: { type: 'string | null', default: null },
  },

  transitions: [
    { trigger: 'trigger:click',         guard: '!isOpen', next: { isOpen: true } },
    { trigger: 'escape:keydown',        guard: 'isOpen',  next: { isOpen: false, activeIndex: -1 } },
    { trigger: 'arrowdown:keydown',     guard: 'isOpen',  next: { activeIndex: 'activeIndex + 1' } },
    { trigger: 'arrowup:keydown',       guard: 'isOpen',  next: { activeIndex: 'activeIndex - 1' } },
    { trigger: 'enter:keydown',         guard: 'isOpen',  next: { selectedValue: 'options[activeIndex]', isOpen: false } },
    { trigger: 'click-outside',         guard: 'isOpen',  next: { isOpen: false } },
  ],

  // ── 样匏规范 ──
  styles: {
    container: {
      background: 'token.surface',
      borderRadius: 'token.radius.md',
      shadow: 'token.shadow.lg',
    },
    trigger: {
      height: 'token.size.input',
      padding: '0 token.spacing.md',
      border: '1px solid token.border.default',
    },
    option: {
      padding: 'token.spacing.sm token.spacing.md',
      states: {
        hover:    { background: 'token.color.primary-50' },
        selected: { background: 'token.color.primary', color: 'white' },
        disabled: { opacity: '0.5' },
      },
    },
  },

  // ── 无障碍规范 ──
  accessibility: {
    container: { role: 'menu', orientation: 'vertical' },
    trigger:   { role: 'combobox', ariaHasPopup: 'menu', ariaExpanded: 'isOpen' },
    option:    { role: 'option', ariaSelected: 'is selected' },
    keyboardNav: ['ArrowDown', 'ArrowUp', 'Enter', 'Escape', 'Home', 'End'],
    focusManagement: 'restore trigger on close',
  },

  // ── 平台适配规则 ──
  platform: {
    web:    { renderAs: 'div + absolute positioning' },
    mobile: { renderAs: 'bottom-sheet', keyboardNavInapplicable: true },
    cli:    { renderAs: 'stdin list', selectedIndicator: '→' },
  },

  // ── 纊束AI 䞍可违反 ──
  constraints: [
    '所有样匏倌必须匕甚 token䞍埗硬猖码',
    'menu 关闭时必须将焊点園还 trigger',
    'option 数量超过 10 时启甚虚拟滚劚',
    '䞍埗修改 spec 文件本身',
  ],
};

这是 AI 生成的组件——䞍是人写的

// 目标框架React 18 + Tailwind
// 生成自dropdownMenuSpec

import { useDropdownMenu } from '@headless/dropdown-menu';
import { tokens } from '@/lib/tokens';
import { useClickOutside } from '@/hooks/useClickOutside';

export function DropdownMenu({ options, triggerLabel }: Props) {
  const { state, actions } = useDropdownMenu(dropdownMenuSpec);
  const ref = useRef<HTMLDivElement>(null);

  useClickOutside(ref, () => state.isOpen && actions.close());

  return (
    <div
      ref={ref}
      style={{
        background: tokens.surface,
        borderRadius: tokens.radius.md,
        boxShadow: tokens.shadow.lg,
      }}
      role="menu"
      aria-orientation="vertical"
    >
      <button
        onClick={actions.toggle}
        style={{
          height: tokens.size.input,
          padding: `0 ${tokens.spacing.md}`,
          border: `1px solid ${tokens.border.default}`,
        }}
        role="combobox"
        aria-haspopup="menu"
        aria-expanded={state.isOpen}
      >
        {state.selectedValue ?? triggerLabel}
      </button>

      {state.isOpen && (
        <div>
          {options.map((opt, i) => (
            <div
              key={opt.value}
              role="option"
              aria-selected={i === state.activeIndex}
              onClick={() => actions.select(opt.value)}
              style={{
                padding: `${tokens.spacing.sm} ${tokens.spacing.md}`,
                ...(i === state.activeIndex && {
                  background: tokens.color.primary,
                  color: 'white',
                }),
              }}
            >
              {opt.label}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

䞀段代码的关系是规范 → 生成䞍是"组件库 → 倍制修改"。


⚠ 这还䞍是终局

这䞪架构有䞀䞪隐含前提我们还䞍借信任 AI所以需芁甚规范文件来纊束它。

劂果某倩暡型区倧到读䞀遍项目就胜理解䜠的讟计语蚀、代码风栌、䞚务语义——它胜从历史代码䞭自劚掚富出规范从 PR review 䞭孊习讟计决策——那规范层也䌚消倱。

                        AI 胜力
                           ▲
                           │
            没有组件库 ─────────────────── ● (未来)
                           │
      规范驱劚生成 ─────────────── ● (这䞪架构)
                           │
      Shadcn 源码拷莝 ──────── ● (现圚)
                           │
  Element Plus npm 包 ───── ● (过去)
                           └──────────────────────► æ—¶é—Ž

届时"组件库"这䞪物种将䞍倍存圚。UI 䞍再是组装出来的而是根据意囟即时生成的。

䜆那䞍是今倩。


🎯 今倩的实甚问题

今倩的实甚问题是圚䞀仜规范胜纊束 AI 的时候我们应该怎么讟计这仜规范

䞊面的架构䞍是答案是䞀䞪锚点。甚来讚论

问题䜠的看法
规范应该写到什么粒床
哪些䞜西必须被纊束
哪些应该亀给 AI 自由发挥
这套架构跟盎接写代码比是省了还是倚了工䜜量

䜠怎么看