前言
为了在团队推广落地组件库,让大家参与到组件库的贡献,准备了一场《组件库开发》技术分享,让大家了解组件库的搭建流程,熟悉组件库项目。
为什么造轮子?
为什么要造一个组件库轮子?毕竟这需要团队投入大量的人力和精力的一件事情。回答清楚这个问题,才能说服领导和同事们知道做这件事情的意义。
首先分析目前使用组件库的现状,对于 Element-ui
组件库来说,目前使用存在不足的地方:
- 官方团队不在维护新增组件功能
- 只提供基础组件,封装的方法、属性都是基本需求的,不够丰富
- 不能定制主题和样式,不满足团队的UI规范
为了解决这个问题,团队在之前也基于 element-ui
开发了业务组件库,针对解决主题的定制和抽象封装项目中复用的业务组件,不过也存在一些不足点
- 主题不够定制化,修改和增加一种主题,要到仓库修改源码
- 组件部分样式不符合 UI 规范标准,使用仍然要改样式,使用成本高
- 缺少必要规范,样式类名随意,容易覆盖影响,没有复用样式,维护成本高
- 设计上宽松,使用一些插件用 webpack 打包,增加冗余代码,不能实现按需加载,打包项目体积大
- 缺少在线文档和使用demo
- 封装组件提供的功能方法少,考虑不全,丢失了 element-ui 组件部分功能,比如 table 组件
需要什么样的轮子
基于上面的问题分析,大概总结一下需要什么样的组件库轮子
- 主题可以一键换肤,封装组件符合 UI 规范统一标准,不需要再修改样式和源码
- 集成基础组件和业务组件,扩展组件功能和数量,提供包体积小,按需加载
- 项目易维护,规范样式、样式隔离打包、单元测试、代码风格统一、版本更新日志等
- 文档配套齐全,组件使用文档,在线 demo 示例代码演示
- 拥抱社区技术,加入 Vue2.7+、Vite、TypeScript 等技术
为什么不能在原来项目基础上改造,要重复创建一个新的项目?这样不是也增加了项目的维护成本?
因为基于项目的架构、技术选型、文档使用方面的考虑,在原来的基础上改造太复杂,不太可行,所以搭建了一个新的项目,后续会将之前组件库功能迁移到新项目上,稳定后替换项目上旧的组件库,统一只需维护一个组件库。
项目介绍
介绍项目中个人认为比较重要的部分,例如架构设计、项目结构、代码规范等
整体架构
整体架构分为两部分:源码仓库和 npm 私有库
-
源码仓库:github 或 gitlab 版本管理代码仓库,统一维护组件源码、组件使用说明、开发文档、在线demo演示等
-
npm 私有库:托管静态资源,管理组件库 npm 包,提供下载源
源码架构设计
单包架构
优点
通过相对路径实现组件与组件的引用,公共代码之间的引用。
缺点
组件完全耦合在一起,每次改动都需要一起打包发布,不能单独下载
所以,选择使用单包架构的话,为了减少包的体积,需要提供按需加载的能力
多包架构
优点
- 每个 package 包彼此独立,单独打包发布,单个仓库多个包
- 无需配置实现按需引用和加载
- 关注点分离,包之间解构,结构清晰,容易维护
缺点
组件与组件之间物理隔离。对于相互依赖,公共代码,只能通过 NPM 包引用的方式来实现。
目标项目使用的是单包架构,考虑到未来业务组件越来越多,进行多包架构升级,容易维护,参考 element-plus
目录设计
技术栈
- 框架&库 Vue2.0、Element-UI
- 主题换肤 CSS 自定义属性和 SCSS
- 开发环境 Vite
- 打包构建 rollup、gulp
- 代码规范 husky、lint-staged、commitlint、eslint、prettier
- 文档主题 vuepress、webpack
项目结构
- build:rollup 构建打包配置文件
- config:项目配置文件
- docs:基于 vuepress 主题文档
- examples:基于 vite 项目开发环境
- packages:组件核心包文件
- scripts:文档部署等脚步文件
- src:项目入口文件
- styles:组件样式文件目录
代码规范化
-
husky:执行 git-hooks 钩子,检查代码规范,常用 pre-commit,commit-msg
-
lint 校验代码: ESlint,Prettier,Stylelint 检查和修复代码格式,统一代码风格
-
commitlint:对 commit messag 进行校验,符合 Angular 团队规范
-
lint-staged:配合 husky,每次提交时只检查本次提交的暂存区的文件
-
更新日志: standard-version 自动生成 CHANGELOG 版本功能更新日志
自定义主题换肤
组件库基于 element-ui 实现,换肤要考虑两个方面,分别对 element-ui 和 组件库的样式进行换肤
1、Element-ui 组件库换肤
实现方式:加载 element-ui 样式文件,通过正则匹配替换主题颜色
2、组件库换肤
实现方式:利用 CSS 自定义属性 和 SCSS 变量定义主题颜色, 通过 element.setProperty
修改主题颜色
CSS 自定义属性
全局CSS自定义属性
在 :root
对象定义属性和属性值,属性名需要以两个减号(–)开始,由 var()
函数来获取值
组件局部CSS自定义属性
为了避免全局覆盖影响,参考 element-plus
设计,组件局部重新定义 CSS 属性,创建局部作用域
样式资源隔离
抽离组件 SASS
样式和变量文件,统一管理样式资源,方便样式复用和维护拓展,然后使用 gulp
打包压缩样式字体资源
开发流程
组件库贡献流程详细步骤
1、fork 项目仓库:https://github.com/JefferyXZF/douluo-ui
2、克隆项目仓库到本地,安装依赖
3、develop 是开发分支,基于该分支创建功能分支,例如 feat-button
4、阅读开发文档,熟悉组件开发规范
5、根据 UI 规范设计和实现组件功能
6、组件测试,编写测试用例和组件说明文档
7、使用 npm run commit
代替 git commit
,提交符合 commit-msg 规范
8、发起 PR 合并前,合并 devleop 分支避免冲突,通知相关人 code review 合并代码
9、更新版本号和日志,打包发布更新 npm,更新项目组件库依赖包
组件开发
组件设计原则
组件库的开发不同于一般的业务组件开发,考虑到组件的拓展性和维护性,需要遵循一些设计原则
单一职责:根据功能拆分组件,且组件粒度不宜过细,前提是复用
组合性:将多个单一职责的小组件组合成为一个职责更大、功能单一的组件,比如时间选择组件是由选择组件、输入组件等组合而成;
封装性:隐藏内部细节和实现意义,并通过props来控制行为和输出(单向数据流)
可测试:一个组件不易于测试,很大可能是组件设计存在问题
组件设计五要素
在实现组件前对组件进行设计,根据功能进行分析,考虑以下几个要素
-
对外扩展属性 - props
-
自身状态 - data
-
事件 - event
-
方法 - methods
-
子视图插槽 - slot
以 button 组件为例
组件实现
- packages 目录创建组件文件,编写实现逻辑
- 在 src/ui 引入创建组件文件,对外暴露注册组件
- styles/src 创建样式文件,common/var.scss 定义组件变量
- styles/src/index.scss 引入组件样式
- compoments.json 定义组件路径打包入口
未来计划
项目升级
- 多包架构
功能迭代
- 单元测试
- 组件按需加载
- 抽象补充业务组件数
技术升级
- vitepress 文档提高打包速度
- TypeScript 保证代码质量
- Vue2.7+ 和 JSX 灵活组件开发