Published on

如何打造一个高可用组件库

Authors
  • avatar
    Name
    McDaddy(戣蓦)
    Twitter

前端界一直有一句传言:

每个前端人都应有拥有一个自己的组件库

这句话是在表名写一个组件库很简单么?我认为不然,一个标准高可用的组件库应该是多种前端领域知识的集合。假设今天你作为一个前端从业者,想要打造一款符合业界标准的组件库,你需要去解决哪些问题

  • 为什么要做一个组件库?
  • 是从零开始还是在某些成熟的组件库上做二次封装?
  • 如何做到好的工程化?比如代码格式/提交规范/CICD等
  • 如何优雅得展示组件库的样例和文档?同时又好维护
  • 如何实现一个高可用的组件?
  • 如何定制主题?
  • 如何处理国际化问题?
  • 如何输出package? esm/cjs/umd?
  • 如何对组件库进行测试?

Why Component Library?

首先我们要明确为什么要一个组件库?

Q:市面上的轮子有很多,五花八门,如果是做一般通用的开发工作已有的轮子肯定是可以满足我们的需求的,为什么还要造一个?

A:轮子虽多,但是每个项目都有自己定制化的功能和需求,以及自己设计的样式,组件库可以弥补通用轮子的不足

Q:那在项目里维护一个common模块,专门存放项目定制的公共组件不就可以了?

A:这确实是之前低成本的最好解决方法,但是它在当今微前端盛行的环境下,已经不能支持项目的扩展。以erda-ui为例,除了主应用仓库外,我们还有企业版仓库,另外还有一个未开源的FDP前端模块。三个git仓库维护在不同的地址,当开发时可以相互独立,但是在部署时又可以通过微前端架构合为一个整体的应用。这种情况如果想要多端都共享这个common文件夹模块就变得非常得不合理

Q:这样用模块联邦应该可以完美解决,将common模块作为一个expose,其他工程用remote去共享它不就好了?

A:如果子项目不是用webpack打包的这招就不灵了,而且这招也必须要在工程间有共同部署的前提下的。如果要快速实现一个现有风格功能的前端项目,但与现有项目无关,这就芭比Q了

开发策略

是从零开始还是在某些成熟的组件库上做二次封装?

这个要从能投入的资源成本来看,如果团队目标就是做一款对标antd这类组件库的开源项目。那一般都是建议从零开始搭建,有的库是基于原生的html元素开发的,比如material-ui,但这种组件库往往更像是一个CSS皮肤,功能性的东西相对较少。另外一种就是如antd这种,主要是基于rc组件做开发的,在增添风格样式的同时,添加了一系列的实用功能,而我们国内目前中台最流行的也是使用antd来做开发。

而对于主要工作还是完成业务,投入资源有限的团队,我们一般都会选择去基于某个成熟组件库来做二次封装,比如erda-ui本身就是基于antd的,所以基于antd做组件库封装就变得顺理成章了

在继承组件库的同时,我们也可以融合一些实用的功能库成为组件库重要的功能,比如引入formily来实现增强的Form功能

工程化

做一个好的组件库,好的工程化实践是必不可少的,这里罗列一些业界必备方案

  • Typescript:无需多言
  • eslint:无需解释,这里推荐f2elint
  • prettier:代码风格统一,同上
  • lint-staged + husky:git hook检查暂存区的代码
  • tsc --noEmit:检查所有类型错误
  • commitizen + commitlint:规范提交msg内容

文档维护

这是组件库能不能够推广开,以及易用性的关键。 即便是做一个只有小组内的公共组件库,如何引导同事,如何指导新人去使用这些公共组件也是一个难题。所以我们需要一个直观可视的文档维护手段,既能查看组件的使用方法API,同时又能看到组件使用的实时效果,要是能够在线编辑试用就更完美了。

这里罗列了国内外的主要解决方案:

  • storybook:国外最流行的方案
  • dumi:阿里出品,简单易用
  • bisheng:antd的方案,易用性比较一般

组件开发

作为公共组件它的开发是必须要区别与普通业务组件的开发,个人认为有以下一些原则需要遵守

  • 标准性 - 各个组件之间应该有统一的代码风格,这里的风格不仅仅指的是代码格式,主要是编码习惯的标准。比如注释的方式、导入导出的方式、变量的命名、方法是箭头还是普通、复杂逻辑是用swtich还是对象映射等等方面
  • 独立性 - 每个组件要遵循单一性原则,保持组件的纯粹性。一个模块只应该完成一个任务,避免逻辑耦合。如果是从业务中抽离的组件,要注意剥离原有业务的逻辑,只抽象出可复用的公共部分
  • 开闭原则 - 写组件前要考虑清楚组件是要达成怎样的目的,尽量API先行,因为这样你才会按目标驱动编码,类似TDD。特别是当组件有自身团队外有使用时,更要做周密的考量,任何对API的随意变更都可能让别人陷入bug的困境之中
  • 可验证性 - 跟纯函数一样,给定输入就应该有稳定的输出

主题定制

TODO