前言:从去年年底开始规划项目的重构,也是这样一个机遇,我开始负责项目的一个基础架构以及一些公共基础服务,主要搭建了组件库以及工具类库来提升后续开发以及重构的效率,期间也是踩了不少坑,接下来就作为整个搭建过程的一个总结,本篇主要是组件库的搭建与实践。
一个项目或系统有着大量的业务场景和业务代码,相似的页面和代码层出不穷,那如何管理和抽象这些相似的代码和模块,这肯定是许多团队都会遇到的问题。不断的拷代码?还是抽象成 UI 组件或业务组件?显然后者更高效。
问题
之前的开发流程从产品设计到研发的过程中,最常出现在需求沟通与研发过程中由于缺少统一的规范和标准化体系来指导实践,导致实施环节各方沟通成本高。
- 认知:产品、研发、设计师对于同一需求都有自己理解的解决方案,缺少统一规范的约束,难以达成共识。
- 效率:设计效率低,交互原型的维护成本及上下游团队的沟通成本高,易造成不专业的印象。
- 品质:认知和效率的局限性,最终导致实施落地的产品质量和用户体验难以得到保障。
价值
组件库最大的价值在于提升整个团队的产研效率,使设计质量得以保障的同时提升产品整体的用户体验。
- 保证产品体验的一致性:对于一个含有多业务系统的大型复杂产品,每个独立的业务系统虽然在功能上有一定区别,但整体的用户体验需要满足基本的一致性。
- 提升设计师的效率:在需求量巨大且需求来自不同的业务线时,需要逐一绘制页面及组件,造成大量重复劳动,并且在评审及需求沟通环节还可能存在不断地细节调优,所以对于设计师而言,组件的高频复用能大大提升设计效率,使设计师更多的将精力聚焦于理解和解决用户的实际问题。
- 提升产研团队的效率:通用场景及普通需求直接按规范进行设计和研发,减少上下游对同一页面及组件使用方式的不同理解而产生的多余沟通成本。
- 利于技术的沉淀:从一个组件库可以扩展到其它的技术方案,比如懒加载、Tree Shaking、文档预览等等。
解决方案
搭建统一的组件库
实践
接下来将详细介绍搭建一个前端组件库需要涉及的流程和相关知识、工具,其中也是参考了一些主流开源组件库的做法。
基础架构
组件库目录结构
目前现在的组件目录结构大致如下:
1 | ├── ... |
组件目录结构
组件的目录结构参考了 antd 的规范
1 | Input |
编译后的组件目录结构
1 | ├── Input.d.ts |
规范
无规矩不成方圆,在组件库开始之初就定义好规范,保证代码的严谨性,配置了以下规则:
- eslint/@typescript-eslint
- stylelint
- git hooks
- git commit
- prettier
组件
基础架构定义好之后就可以愉快的进行组件开发了,组件的基本开发流程:
- 组件初始化
- 代码 coding
- 组件 demo
- 组件文档说明
- 组件库入口文件导出组件
对于组件初始化,我们也是通过脚本自动化实现,减少这些繁琐重复的工作。
样式
对于组件的样式,一开始我们有两套方案:
- 常规样式(css/scss)
- CSS-in-JS(styled-components)
我个人的话更喜欢 CSS-in-JS 的方案,不用去考虑样式的打包以及引用方式,但最终考虑到业务场景还需要输出原生的 css 代码提供旧项目引用,所以最后也是采用了常规样式,通过 gulp 打包输出 css 以及 scss 文件,后面打包的时候也会具体介绍一下。
文档
这里介绍一下目前的文档说明以及文档生成方案,首先对于每一个组件,需要在开发组件时编写好组件的说明文档(规则格式看下面组件文档)以及 demo,当我们运行组件库文档预览项目时会通过 node 脚本读取组件的说明文档以及 demo 自动生成对应的路由文件,这样我们就能实时预览文档以及 demo 演示。
组件文档
1 | ## Input |
组件库文档
组件库的文档一般都是对外可访问的,因此需要部署到服务器上,同时也需具备本地预览的功能。
可以自己搭一个文档站点,也可以使用目前主流的文档生成器(Docz、Storybook、VuePress)来生成文档站点。
这里我们采用的是自己搭建的一个单独的 React 项目,也就是上面的 docs
文件夹,其实自己搭也比较简单,首先是思路:
readFile
读取src
下组件的 md 文件和 demo 文件保存起来writeFile
写入路由配置以及对应的路由文件- 通过不同的路由渲染对应的组件文档和演示
主要借助的是 node 读写文件的便捷性,对于文档自动生成方案在后面文章会具体介绍一下,先明确一下思路就行。
打包
对于打包后的文件,统一放在 ems
目录下,顾名思义我们需要打包成 ESModule
的规范。
1 | // packages.json |
编译打包 ts[x]
在入口文件我们需要以 ESModule
的规范导出组件:
1 | export { default as Input } from "./components/Input"; |
打包工具的话我们就不能使用 webpack
来打包我们的组件库,可以使用 rollup
或 TS
来编译组件,这里我们采用的是 TS
编译的方案,配置 tsconfig.build.json
:
1 | { |
编译打包样式文件
上面我们已经成功编译了 ts
或 tsx
文件,但是对于我们的样式文件还没处理(TS 无法编译样式文件),样式文件根据我们上面的代码规范,需要打包编译到对应的组件文件夹下,这样就可以跟着组件路径来引入:
1 | import "@hzzly/components/esm/input/style"; |
这里我们采用 gulp
来处理样式文件:
1 | // 生成css到对应组件 |
UMD
这里还有一个业务场景是 JsComponents
需要打包成 umd
的格式提供旧框架通过链接的方式直接引用,所以我们还配置了 umd
的打包规范,分别单独打包 js 原生组件, 将组件单独打包需要在 Webpack 中配置多个entry
,大致配置如下:
1 | const entry = {}; |
迭代维护
CHANGELOG.md
组件日常维护占整个组件库生命周期的很大一部分,组件库做起来了以后,组件功能后续会不断迭代,也许是 bug fix,也可能 feature,这些组件的迭代我们通过 PR 和 issue 来管理,同时,我们需要管理好组件的 changelog,为了规范我们也是将 changelog 维护到一个 Markdown 文件里,通过 conventional-changelog
工具自动根据 commit message 生成 CHANGELOG.md**。
总结
到这里,也算是对最近在组件库的探索做了个总结,从零开始构建了一个比较完整的组件库,这段经历也是让我在架构思维以及业务层面有了新的认识,也学到了不少的知识。当然,还有很多不完善的地方,也是在慢慢优化完善,在组件化这条路上,我们还有很多事情要做,加油!!!