前端唯一的护城河?结合 AI 将字节组件库 Headless 化后的感想~
首先说明一下,我自己潜心研究国内外组件库源码大概有两年时间了,例如国外的chakra-ui,shadcn ui,floating-ui组件库, 国内的ant-design、字节的arco-design, 腾讯的Tdesign组件库的源码。(偶尔发现源码 BUG 提的 PR 也合并了)。
也做过两个组件库的编写,改造过程中一个很深的感触就是 AI 从 0 到 1 造Ant Design/Arco Design级别的组件几乎不可行(你可以立马试试),甚至可以说是写的是垃圾代码, 必须有一个资深以上开发本身就了解这些组件的架构和核心技术细节的前提下,AI 才能在辅助层面极大的提高开发效率。
简单总结就是: AI 的产出代码质量好坏完全取决于开发者本身的技术水平。
虽然很多营销号宣称“AI 无敌”,只要几句话就能生成一切,但客观地说这些营销号的作者大多数并没有拿出很多自己开发经历的经验和开源出来的作品作为证据。
本文主要案例来自从源码层面改造字节的组件库Arco Design的表单组件Form(改造了很多组件,这篇文中着重拿 Form 表单举例)。欢迎访问网站
(组件库教程社区 | React & Headless UI) 查看改造后的Form组件具体功能和API。
好了,我们继续之前的headless的概念往下说。
现状:国内 B 端的“硬核”与 “枷锁”
虽然 Headless 组件库如此流行,但在国内 B 端市场,情况有些特殊:以Ant Design为代表的大厂系组件库(如字节的 Arco Design / Semi Design、腾讯的 TDesign 等)稳坐头把交椅。
坦白说,它们处理极其复杂业务场景的能力(联动、嵌套、动态校验等),确实远超国外的Headless库。这也是为什么国内开发者至今仍难以割舍这些组件库的原因。
但在全面拥抱 AI 编程的今天,这些传统的组件库无论是样式覆盖,还是通过修改 CSS 变量来定制样式,对 AI 来说都存在“适配性断层”——因为 AI 最擅长的是从零生成样式,而不是在已有的层层样式嵌套中搞魔改。
那么,一个硬核的问题摆在了我们面前:
我们能否既保留Ant Design极其强大的逻辑处理能力,又让它彻底“Headless 化” —— 也就是把 100% 的视觉控制权交还给开发者?让 DOM 结构的控制权交给开发者?
答案是肯定的,但问题就在于改造的难度非常大。为什么呢,我们来举一个实战翻车案例:
案例分析:一个“暗藏杀机”的 validate 需求
我举个典型的例子。在重构 Form 组件的校验方法时,我们需要一个支持多种调用方式的 validate 函数:
- 回调函数模式:
this.form.validate((errors, values) => { ... }) - Promise 模式:
this.form.validate().then(values => { ... }) - Async/Await 模式:
const values = await this.form.validate()
为了实现这个功能,在Arco Design源码中是这样做的,首先它用一个高阶函数promisify来对原始校验逻辑进行包装。
// 核心逻辑简述 public validate = promisify((...args) => { // 省略复杂的校验逻辑... const promises = controlItems.map(x => x.validateField()); Promise.all(promises).then(result => { // 逻辑处理... if (Object.keys(errors).length) { callback?.(errors, cloneDeep(values)); } else { callback?.(null, cloneDeep(values)); } }); });而 promisify 的内部实现,最关键的一行是判断用户当前的调用意图的 if 语句:
function promisify(fn) { return function (...args) { // 关键判断:如果最后一个参数是函数,说明用户在用回调模式 if (typeof args[args.length - 1] === 'function') { return fn.apply(this, args); // 直接执行,不返回 Promise } else { // 否则,返回一个全新的 Promise 实例 return new Promise((resolve, reject) => { // ...将原始函数 Promise 化 }); } }; }而在重构这部分代码的时候,我希望优化this.validate内部逻辑,并去掉promisify, 用来减少代码量,但遗憾的是这么一个小小的需求, AI 会在这里“集体翻车”。
我测试了目前市面上最顶尖的模型:Claude 4.7 (Opus), GPT-5.4, Gemini 3.1 Pro。
在我没有明确提示的情况下,没有一个模型能自动识别并改造出兼容this.validate多种用法的代码。它们要么粗暴地全部转化为Promise,要么干脆破坏了原有的回调链路。(核心是一定要判断this.validate()中最后一个参数是否是回调,如果是就不要包装为Promise, 否则只保留之前版本回调的用法)。
只有在我明确指出错误, 并且加入限定的提示词后,它们才会像“挤牙膏”一样修正。
很多类似体验让我深切感受到之前提到的结论:如果使用者本身技术不够扎实,在面对这种复杂基础设施代码时,AI 写出的代码,很难察觉到它异常的地方。
同时对我们打工人来说有个非常矛盾的使用AI的问题浮现出来:
对于我们打工人来说,AI 犯错,顶多是生成了一段 Bad Code;但人犯错,可能你人就被裁了或者影响你的绩效。
传统组件库在 AI 时代的局限性
说到这里,可能有同学可能会问:传统的组件库如Ant Design,AI也能帮我改样式啊,为什么非要搞Headless?
这里我们要纠正一个认知偏差:AI最强大的能力是“生成”,而它最痛苦的能力是“魔改”。
Ant Design 目前的 UI 方案对 AI 并不友好
目前国内类似 Antd 的组件库仍然是以改变CSS变量的方式定制 UI, 这就带来两个核心问题。
- 一个组件能定义的 CSS 变量有限,并不能随心所以修改 UI
- 另一个是组件内部 DOM 结构固定,外部是无法修改的 这就导致 AI 并不知道 Antd 组件源码的 DOM 结构。并且修改的 CSS 变量也是基于语义化,而不是真的知道源码 DOM 结构上下文而做出精确修改。
所以传统组件库像是一个高度集成的“黑盒”。这是对 AI 非常非常不友好的。
而在Headless模式下,所有的DOM结构都是你(或者 AI)亲手写出来的。AI对它生成的代码拥有 100% 的上下文掌控力。它不需要去猜测黑盒里的逻辑,它只需要根据你的描述,在逻辑钩子外结合任何CSS框架,例如Tailwind CSS,UnoCSS,Sass等等。
现实中类似的样式历史债务比比皆是
我相信大多数做过复杂 B 端项目的团队都遇到过一个问题,就是 UI 有自己定制化的样式,然后你不得不去覆盖Ant Design的样式, 我直接给你看飞书文档中(他们前期部分团队应该用的Ant Design),这样国内的顶级团队依然有这样的问题。
以下是飞书问卷页面,我随手截图的内容,这种覆盖的样式如下:
而这只是一个按钮的CSS样式,团队自定义后的样式覆盖情况(覆盖了起码有 4 次)。连字节核心产品都这样,你就可想而知这是一个多么普遍的问题了。
核心问题就在于多团队合作的时候,在这种提供完整 UI 的组件库里是很难避免样式覆盖问题的(以为 CSS 类已经写死在组件里了)。即使现在使用 CSS 变量来控制 UI 样式。
Headless 组件的优势举例
我相信绝大多数前端有过后台管理系统的经验,都会用过Ant Design的 Form 组件,其中Ant Design的 Form 组件在布局中最大的问题在于,其本身将固定的栅格布局系统嵌入其中,代码如下(注意labelCol={{ span: 8 }}和wrapperCol={{ span: 16 }}):
import React from 'react';