【从 0 到 1 搭建 Vue 组件库框架】0. 系列导论
导航
2. 在 monorepo 模式下集成 Vite 和 TypeScript
(编写中)3. 集成 lint 代码规范工具
(编写中)4. 定制组件库的打包体系
(编写中)5. 设计组件库的样式方案
(编写中)7. 接入单元测试与集成测试
(编写中)8. 版本管理与发布机制
(编写中)9. 实践持续集成
(编写中)10. 优化组件库的使用体验
(编写中)11. 实现 cli 工具复用研发成果
不仅仅是组件库
我在 2021 年 9 月正式参加社会工作,接手了一个千疮百孔的 Vue2 屎山项目。在近两年的时间里,我在这个项目中不断地折腾,做了 Vite 迁移、Vue3 迁移、pnpm 迁移、monorepo 改造、集成测试等各种调整。我不希望这些辛苦积累的经验与知识随着时间的推移流逝,趁着这次公司内部分享的机会,我将对这两年在工程化方面做的探索进行一个梳理与归纳。
这个系列分享的标题叫做《从 0 到 1 搭建 Vue 组件库框架》,但是所讲述的内容绝不仅仅是搭建组件库框架。
我们也许会认为,一个组件库的精髓在于体验设计、设计模式、API 易用性、兼容性、稳定性、性能等等。实际上,源代码之外的工程化基础设施也是一笔巨大的财富。我们所看到的开源的组件库,基本都已形成了一套非常成熟的工程化体系,覆盖了依赖管理、代码规范、打包构建、版本管理与发布、自动测试等多种场景。
因此,组件库的搭建算得上是前端工程化实践的集大成者,我们选取这个场景能够更多更好地介绍前端工程化相关的内容。
我们的目标是知其然更知其所以然,希望能够以组件库搭建的实战入手,逐步掌握工程化的思路与实践,最终不仅仅是搭建组件库的程度,而是可以灵活地组合各种工具,自由地定制前端工程的各种细节,当然也包括日常 Web 应用的架构。你在这里学到的任何内容,完全可以应用到自己的日常开发中去。
目标
实践过程将会在分享中占有很大比例,因此我们需要努力打造一个相对逼真的学习环境。
我们从一个 MVP(最小化可行性产品) 开始,在每一个章节确定新的目标,不断地添加特性,就如同实际项目的工程化一般,通过慢慢的积累和迭代不断向理想的形态演进。
文章涉及到的所有步骤都会附有代码或者操作命令,争取使读者能够按照步骤一步步地搭建出目标工程。
先预告一下实践操作的技术栈:
- pnpm 为工程提供包管理服务。
- Vue 作为组件库的框架基础。
- Vite 作为主力构建工具。
- TypeScript 提供类型支持。
- VitePress 搭建文档示例网站。
- Vitest 处理单元测试
- Playwright 处理 E2E 测试。
- 规范系列工具:ESLint、Stylelint、commitlint 等
- Changesets 处理版本发布
- Github Actions 提供持续集成服务
技术栈并不是决定性因素,我认为对于工程化实践而言,了解方向和思路要比了解细枝末节更加重要。我会在分享中努力讲清楚其中的思路,如果能做到知其然更知其所以然,相信你也能用 React
+ Webpack
+ Jest
搭建起同样的架构。
通过这一系列文章,你将会有以下收获:
- 获得一次相对完整的搭建组件库的实战经验。
- 建立前端工程化的整体思路,吸收优秀实践,可用于指导日常开发中遇到的相关场景。
组件库基础设施的构成
那么,我们的组件库工程究竟要做成什么样子呢?在造轮子之前,我们不妨先去参考他人。我们选取当下非常成熟的一款 Vue UI 组件库 —— Element Plus 作为参考对象吧。先前往 element-plus 代码仓 去看一看成熟的组件库都是怎么做的。
这里提示一个小技巧,在 Github 的代码仓页面,给域名中的 github
加上 1s
后缀,就可以前往在线版的 VSCode
编辑器浏览代码,获得更好的体验。这个功能是来自于开源项目 github1s。
- https://github.com/element-plus/element-plus
+ https://github1s.com/element-plus/element-plus
也可以在代码仓页面按下键盘上的句号(.
)按键进入 Github 官方的 Web IDE。
目录结构
我们看到 element-plus
是通过 monorepo
的方式,将整个 UI 组件库的多个依赖模块都整合到了同一个代码仓中,以其代码仓中的 packages
目录为例子。
📦element-plus
┣ 📂...
┣ 📂packages
┃ ┣ 📂components # 各种 UI 组件
┃ ┃ ┣ 📂button
┃ ┃ ┣ 📂input
┃ ┃ ┣ 📂...
┃ ┃ ┗ 📜package.json
┃ ┣ 📂utils # 公用方法包
┃ ┃ ┗ 📜package.json
┃ ┣ 📂theme-chalk # 组件样式包
┃ ┃ ┗ 📜package.json
┃ ┣ 📂element-plus # 组件统一出口
┃ ┃ ┗ 📜package.json
┣ 📜...
我们注意到,在 npm.js 上是可以查到这些对应的包的。
像 element-plus
这样将一个大型项目的多个模块集中在一个仓中进行开发的方式,我们称之为 monorepo
模式,这也是大部分现代前端组件库会采用的文件组织方式。它的优势非常多,用代码权限管控上的缺陷,换来了统一的工程配置、便捷的依赖维护、快速修改响应(相关阅读:Monorepo - 优劣、踩坑、选型)。我们的示例项目也会采用这样的方式开发。
相关章节:
2. 在 monorepo 模式下集成 Vite 和 TypeScript
代码规范
element-plus
是一个多人协作的开源项目,会有大量的贡献者提交代码,这其中会涉及到个人编码风格的多样化导致项目代码可维护性下降的问题,完全通过人工审核控制代码规范的成本又过于高昂。因此组件库项目往往会集成各类 lint 规范,通过自动化的手段保障 Clean Code。这其中包含了:
- 保证脚本代码规范的 ESLint
- 保证样式代码规范的 Stylelint
- 保证 git 提交信息规范的 commitlint
- 设置编码风格的 Prettier
在我们的示例项目中,也会带领大家集成这些代码规范工具。
相关章节:
(编写中)3. 集成 lint 代码规范工具
打包构建
检查 element-plus
的 internal/build 目录,发现了一套为自身组件库量身定制的构建模块,它是基于 Rollup API 的自定义构建脚本。
为什么要定制这样复杂的构建体系。一方面,代码仓中多个组件的打包流程有许多公共重复的部分,统一封装后有利于集中管理。另一方面也是为了生成可用性尽可能高的产物,这个目的使得构建变得复杂起来,我们可以从 package.json
看出 element-plus
到底构建出了多少不同规格的产物。
// 摘自 element-plus 的 package.json
{
// cjs 入口
"main": "lib/index.js",
// esm 标准入口
"module": "es/index.mjs",
// d.ts 类型声明入口
"types": "es/index.d.ts",
"exports": {
".": {
"types": "./es/index.d.ts",
"import": "./es/index.mjs",
"require": "./lib/index.js"
},
"./es": "./es/index.mjs",
"./lib": "./lib/index.js",
"./es/*.mjs": "./es/*.mjs",
"./es/*": "./es/*.mjs",
"./lib/*.js": "./lib/*.js",
"./lib/*": "./lib/*.js",
"./*": "./*"
},
// 为 <script> 直接引入提供的全量版本,上传到 unpkg 和 jsdelivr cdn。
"unpkg": "dist/index.full.js",
"jsdelivr": "dist/index.full.js",
}
前端的运行环境是复杂的,最大限度地保证产物的可用性并不是一件容易的事情,你可能需要解决以下问题:
- 组件库支持在
html
中通过<script>
全量引入吗? - 组件库在前端工程中,能否在构建工具的配合下,同时支持
require
、import
不同的引入方式? - 组件库能不能提供完整的类型支持,在 IDE 中对用户进行友好的类型提示?
- 在确保上述条件的基础上,能否最小化产物体积?
相关章节:
(编写中)4. 定制组件库的打包体系
样式
element-plus
的 packages/theme-chalk 目录,使用 Sass 预处理器构建了一套主题预设方案,使得用户可以个性化地修改组件的主题样式。
我们为自己的组件库制定样式方案时,也会基于以下几个角度思考:
- “换肤能力”称得上是当下组件库的标配,我们的方案能支持主题切换功能吗?
- 如何尽可能地减少组件库样式与用户样式的冲突?
- 如何让用户方便地修改微调组件样式?
相关章节:
(编写中)5. 设计组件库的样式方案
文档
文档是否友好也是评价一个组件库是否好用的重要标准。element-plus
有全面完善的官方文档,兼具组件效果展示、代码展示、甚至还有对网络环境要求不那么高的在线演示 Playground。
做好组件库的文档并不是一件简单的事情,其中也有很多值得思考的问题:
- 用什么工具能够兼顾搭建效率与定制的灵活性?
- 组件源码怎样直接复用到文档中?
- 能不能尽可能地提高自动化生成内容的比例,避免频繁地手动维护,比如组件 API 说明有没有可能通过源码自动生成?
- 如何搭建在线演示 Playground?
相关章节:
测试
测试完善度是我们是否选用一款组件库的重要指标,element-plus
拥有 84% 的测试覆盖率,足以说明其作为开源软件是相对成熟可靠的。
element-plus
每个组件目录下的 __tests__
存放了对应组件的单元测试内容,比如:github.com/element-plu…__
完善的单元测试也极大地提高了项目的可靠性,集成到 CI 系统后,在每次合并代码前进行单元测试检查,可以提前识别重构或变更带来的风险。
除了单元测试之外,我们还会对端到端的 UI 测试进行一些探索,从用户交互的角度补充一些测试用例,让项目的可靠性防护更加扎实。
相关章节:
(编写中)7. 接入单元测试与集成测试
发布
我们注意到 element-plus
的版本发布,或者说成熟项目的版本发布都有着一套连贯的流程。
- 将新版本构建出的产物发布到
npm
仓库。 - 基于发布分支,用版本号给代码仓打
tag
。
- CHANGELOG 文件会自动根据 github 相关信息,生成特性更新条目。
实现这些能力,需要我们了解 npm
组件发布的优秀实践,并集成一款成熟的发布工具。
相关章节:
(编写中)8. 版本管理与发布机制
持续集成
element-plus
的 .github/workflows 目录下存放了各种各样的 Github Actions
剧本。Github Actions 为绝大多数开源项目提供了便捷的持续集成功能,将原本零散的构建、规范检查、测试、发布等流程以流水线的方式串联起来。
我们会以下面三个最关键的场景为核心,去实践持续集成:
- 代码合并门禁检查。
- 自动测试。
- 发布 / 部署流水线。
相关章节:
(编写中)9. 实践持续集成
其他
至此我们完成了对 element-plus
的洞察,大致了解了一款成熟的组件库在工程化方面需要做哪些事情,确定了一个比较清晰的前进方向。
但是,工程化实践的技术积累不应当仅仅停留在文字。最后,我们是否能实现一款命令行工具,自动为我们完成这些复杂的配置,使得下一次需要初始化项目时,做到一键生成,零配置开工呢?
相关章节:
(编写中)10. 实现 cli 工具复用工程化成果
结尾与资料汇总
最后,我诚挚地邀请大家一起来学习,希望我们能够清晰地掌握前端工程化的优秀实践,扎实地搭建出自己的组件库。之后我将以 1 - 2 周完成一篇文档的频率逐步完善这个系列。如果你发现了文章中的错误与不周全的地方,或者有更新更好的思路,欢迎在评论区指正。
本章涉及到的相关资料汇总如下:
官网与文档:
开源项目 github1s:在线 VSCode 阅读 github 代码
分享博文:
转载自:https://juejin.cn/post/7254341178258505788