闽公网安备 35020302035485号
最近我接手了一个隔壁组转过来的中后台重构项目。
交接的时候,对方的技术负责人特意跟我强调,说这个项目采用了最新的技术栈,全面拥抱了Tailwind CSS,开发体验极其丝滑。
我当时心里还挺期待,毕竟这两年Tailwind的风刮得太大了,各种国内外大佬都在疯狂带货。结果周末我抽空把代码拉下来,打开VSCode准备梳理一下业务主流程。盯了屏幕不到十分钟,我感觉自己的眼睛快瞎了。
光说理论没意思,我直接给你们截取一段真实的、承载了各种表单校验和状态联动的业务侧边栏组件。你们自己品鉴一下所谓的极致开发体验👇:
const OrderCard = ({ order, isAdmin, isExpanded }) => {
return (
<div
className={`flex flex-col w-full p-5 mb-4 border rounded-lg shadow-sm transition-all duration-300 ${
isAdmin ? 'bg-red-50 border-red-200' : 'bg-white border-gray-200'
} ${
isExpanded ? 'max-h-[800px]' : 'max-h-24 overflow-hidden'
} hover:shadow-md cursor-pointer`}
>
<div className='flex items-center justify-between pb-3 mb-3 border-b border-gray-100'>
<span className='text-sm font-semibold text-gray-800 truncate w-[60%]'>
{order.id}
</span>
<span
className={`px-2 py-1 text-xs rounded-full ${
order.status === 'PAID'
? 'bg-green-100 text-green-700'
: 'bg-orange-100 text-orange-700'
}`}
>
{order.statusText}
</span>
</div>
{/* 内部极其复杂的业务字段渲染... */}
</div>
);
}
代码跑得通吗?当然跑得通。UI 还原度高吗?也挺高。 但是作为接下来要维护这个项目的组长,我只觉得一阵头皮发麻。
很多前端新人,甚至是做惯了C 端独立开发的兄弟,对Tailwind简直是顶礼膜拜。因为它不用取名字,不用在JS和CSS文件之间来回切换,写起来确实有快感。
但作为趟过无数中后台项目的深水区,我今天必须给这股跟风热潮泼一盆冷水: 在绝大多数重型中后台业务场景里,Tailwind CSS 并不是什么神兵利器,而是给后期维护带来不方便。
来,咱们拿真实代码说话,看看它到底是怎么摧毁中后台工程的👇。
对了。顺嘴提一句,技术大厂,前后端-测试机会,全国一线及双一线城市均有[坑位],待遇和稳定性还不错,感兴趣看看。
做中后台系统,最难的从来不是画 UI,而是处理极度复杂的数据状态流转。
上面那段代码最大的问题在于信噪比极低。作为一个接手代码的前端,我点开这个文件,首先想看的是:这个组件在不同权限、不同展开状态下,业务逻辑是怎么走的?
但在Tailwind的体系下,我的视线全被flex、p-5、mb-4、max-h-[800px]这种毫无业务价值的视觉原子类给强暴了。如果退回到老古董的CSS Modules方案,这段代码在JS侧应该长什么样?咱们对比一下:
import classNames from 'classnames';
import styles from './OrderCard.module.less';
const OrderCard = ({ order, isAdmin, isExpanded }) => {
return (
<div
className={classNames(styles.orderCard, {[styles.adminMode]: isAdmin,
[styles.expanded]: isExpanded
})}
>
<div className={styles.cardHeader}>
<span className={styles.orderId}>{order.id}</span>
<span
className={classNames(styles.statusBadge, {
[styles.statusPaid]: order.status === 'PAID',
[styles.statusPending]: order.status === 'PENDING'
})}
>
{order.statusText}
</span>
</div>
{/* 业务字段一目了然 */}
</div>
);
}
发现区别了吗?重构后的JSX变得极其纯粹。我只通过adminMode、expanded这种类名,就极其清晰地传达了业务语义。至于那个订单编号到底占百分之几十的宽度,那是UI 层该关心的事情,它安静地待在.less文件里,绝不会来污染我的业务主逻辑。
中后台业务是不可能脱离Ant Design、Element Plus这类重型组件库的。而组件库的本质,是封装好了一整套内部的DOM结构和ClassName规范。
这就带来了一个极其致命的冲突:当你用Tailwind去覆盖Ant Design的内部样式时,你会写出极其恶心的Hack代码😖。
比如产品经理要求:在这个特定页面里,把Ant Design表格的表头背景色改成浅蓝色,单元格的padding改小一点。
正常的Less做法是用样式穿透,精确打击:
/* 样式文件覆盖 */
.myCustomTable {
:deep(.ant-table-thead > tr > th) {
background-color: #f0f8ff;
padding: 8px 16px;
}
}
你知道那个拥抱Tailwind的小伙子是怎么写的吗?为了不写CSS文件,他强行使用了Tailwind v3+的任意变体语法:
// Tailwind 强行覆盖组件库内部样式
<Table
className='[&_.ant-table-thead>tr>th]:bg-blue-50[&_.ant-table-thead>tr>th]:py-2 [&_.ant-table-thead>tr>th]:px-4 [&_.ant-table-tbody>tr>td]:text-gray-600[&_.ant-table-tbody>tr>td]:py-2'
dataSource={data}
columns={columns}
/>
这段代码合进主分支的时候,我都替后续维护的兄弟感到悲哀😢。
这玩意儿连换行都没有,密密麻麻挤在一起。未来如果要做主题切换,或者升级Ant Design导致内部类名变了,谁敢去动这坨连正则都极难匹配的字符串?
不仅没有提高开发效率,反而为了强行凑Tailwind的语法,写出了一堆极难维护的代码。
一行代码被写出来的成本,远远低于它在未来三年里被维护的成本。
Tailwind本质上就是披着ClassName外衣的行内样式。它把所有的样式固化在了HTML结构上。
设想真实的维护场景,前任开发为了让一个按钮和旁边的输入框对齐,极其随意地写了一个向左偏移负间距的类名:
<Button className='-ml-2 mt-1'>提交</Button>
半年后你接手这个需求,产品要求在这俩元素中间加一个Icon。你看着这个-ml-2和mt-1会陷入极其痛苦的挣扎:他当时为什么要写负边距?是因为外层父元素加了错的padding导致的?还是为了抵消Button内部自带的margin?🤷♂️
在传统CSS中,我们往往会留有注释说明抵消输入框自带的右侧留白。但在Tailwind里,没有注释的容身之所。
为了保证不出线上Bug,你绝对不敢删掉那个-ml-2。你会选择在它后面再打个补丁,加个pl-4试图把它顶回来。 第二年,另一个接手的同事遇到了错位,又在后面补了一个mt-[-5px]🤣🤣🤣。
日积月累,HTML标签上的类名越来越长,死代码和冲突代码全堆在DOM上,最终变成一座没人敢碰的屎山💩。
说了这么多,难道Tailwind真的就是垃圾吗?当然绝对不是。
如果你在做偏C端的炫酷落地页、做SaaS官网,或者你是独立开发者,没有沉重的历史包袱,不需要配合复杂的重型组件库,那Tailwind绝对是神作。它自带极其优秀的设计规范,能让你极速堆出好看的界面。
但咱们讨论的是中后台。中后台是干嘛的?团队十几个人来回交接,动辄几百个页面,充斥着极其复杂的表单联动和权限校验,生命周期长达五年甚至十年。
在这种重型项目中,保持业务逻辑的纯粹性,分离关注点,远比你少写几行CSS要重要一万倍。
好了,今天分享到这,谢谢大家😁
——转载自:ErpanOmer