Vue组件库 | 如何从0到1开发一个开源组件库

40,231 阅读10分钟

写在前面

本文可能无法从细节层面教会你如何做好一个开源组件库,作者也在不断探索和学习,但是也许会对你有所启发。这篇文章既是分享,也是记录,在写这篇文章的此刻,已经是作者一拍脑袋要做一个开源项目将近一年之后了。一年以前作者对于如何开发一个组件库一无所知,对于开源项目也是了解甚少,抱着什么不会学什么的态度,作者拉上了两位好友开始了Varlet的开发。

Varlet组件库相关链接,希望多多鼓励和支持

Github仓库
中文文档
英文文档

设计背景

组件库设计之初是因为作者上一家公司对于当时使用的库的设计风格不是很满意,并且有升级Vue3的计划,希望能有一个更有质感并且视觉效果更加强烈的设计风格。但是由于公司并没有能力设计出这样一个Design System,市面上也没有符合要求的移动端开源组件库,所以作者有了自己依赖一些现成的Design System做一个新的组件库的念头。但是公司对于自研组件库的想法不是很在意,没有企业支撑, 作者还是希望能把自己的想法落地实现,所以慢慢便成了个人向的开源项目。

邀请伙伴

做一个开源项目一定要有自己信赖的伙伴,避免许多功能自己一拍脑门就去设计了,由于每个人的技术栈和技术思想并不完全相同,即使你很有经验,伙伴们也会看到许多你看不见的事情。 如果你在企业,可以邀请你的同事。如果你是个人,可以邀请你信赖的朋友,或是到掘金发文章,发圈子沸点,找到那个跟你有一样兴趣的人。

一起学习主流方案

毕竟做什么事情都要有基础,有多个学习的对象,在我们什么都不会的情况下,我们需要学习主流的组件库架构方案,我们学习了vant, vuetify, element, element-plus, material-ui,muse-ui等等许多组件库的架构思想, 一边摸索一边思考适合自己的实现。

Monorepo 架构

我们采用了拆包的架构, 主要是通过yarn workspacelerna实现,好处在于我们可以把通用的依赖都做成一个包进行单独发布,在构建组件库的过程中也可以同时产出一些实用的工具,也为后期项目的扩展打下了基础。同时lerna有着完善的发包机制,让我们不需要太关心包和包之间的依赖关系。组件库则设计成其中的一个子包,所以Varlet在未来可能不会仅仅是一个组件库,随着包的增多可能会变成一个解决方案,实际上我们也正在朝这个方向探索。

Design System

首先,作者不建议在没有设计系统的情况下进行组件库的开发,因为自己拍脑门想出来的设计总是会那么的不合理。如果企业有自己的能力设计一个风格或是设计系统那是最好的选择。 如果像是作者这样的倒霉蛋,也最好选择开源并且成熟的设计系统。比如我们选择了Material Design,作者的一个朋友也正在做自己的组件库,他选择了Vercel Design,这里是他的 Github仓库 有兴趣的可以去看看,捧个场,我们应该尊重每个有分享精神的人。

uisdc-yk-20181104-69.jpeg

相关工具

构建一个组件库,需要的工具又广又杂,我们考虑到一个成熟的组件库至少应该满足以下最基本的开发要求

  • 开发环境,你得起个服务去调试代码吧
  • 支持按需引入,应该没有人愿意全量导入组件库把
  • 组件库编译,生成umdesm模块的组件代码
  • 构建开发文档,至少得有个中文文档说明一下组件怎么用吧
  • 单元测试,你写的代码得信的过吧
  • 桌面端和移动端的组件预览,你得让使用者看到组件具体长什么样子吧
  • 代码格式化和规范检测工具,毕竟是团队作案,没有规矩不成方圆
  • 自动化的文档部署和测试流程,总不能每次发布版本都手动去部署文档和测试吧

所以我们决定自己实现上面所有的功能,并且单独抽了一个子包,叫作Varlet-Cli,这个包如今也开源了出来,很大程度上降低了开发组件库的门槛。使用手册在 这里 ,具体实现可以去我们的 Github仓库 去看源码

开发环境

我们的开发环境采用了webpack5webpack-dev-server构建了一个官方文档站点,基于我们自定义的插件进行了src目录的扫描,提取出了有用的信息并构建了基础的路由和文档配置。关于文档编写我们是通过varlet-markdown-loadermd文件编译成了vue template string渲染在了每一个路由模块中,使得文档编写更加容易。

为什么不是Vite

说句实在话,在我们去年十月份准备开始动手的时候,Vite并不稳定,现在也没有一定要换Vite作为开发环境的理由,或许以后有更换的可能,但是我们目前还是会将精力聚焦到更重要的事情上,对于个人开发者来说,合理安排时间做更有效的产出是最重要的。但是对于一个新的项目,我认为Vite应该是第一选择,因为它真的非常非常优秀

组件库编译器

在有了开发环境之后,我们还需要把我们的组件代码导出成umdesm模块来提供给用户使用,这里我们讨论之后没有使用rollup,而是选择自己实现组件库的编译器。编译组件其实核心就是扫描整个目录,扫到什么格式的文件就用对应的编译器去过一遍他,这个没什么难度,自己实现可以在编译过程中添加很多的优化,并且是完全自由可控的,可以生成我们希望生成的模块结构,也方便我们实现按需引入,事实也证明了,这很值得。

组件原型设计与重构

当我们开始面向具体的场景进行组件开发的时候,我们会各自阐述自己对于这个组件的理解,并且由负责这个组件的人牵头去做原型开发,也就是草稿,因为talk is cheap,所以需要定一个大概的雏型并做具体实现。当原型开发结束之后,我们再次对原型进行评审,进行深入的讨论,最后负责该组件的人会对组件进行重写,确定api,补全文档,完成单测,最后发布。不要畏惧重写和推翻,也不要奢求一步到位,是我们慢慢总结出来的一些经验之谈。

组件单元测试编写

为了组件的稳定性以及减少维护压力,每个功能都需要进行完善的单元测试,我们使用jest + @vue/test-utils进行测试,这两个包也是vue官方推荐的,虽然可能需要自行封装一些手势相关的工具函数,但是总体来看还是比较轻量易用的。然后需要使用jest生成测试报告,并托管到codecovcodecov是一个开源的测试结果展示平台, 可以将测试结果可视化。

截屏2021-09-22 上午12.24.49.png

截屏2021-09-22 上午12.39.00.png

组件发布

我们遵循semver 语义化版本规范, 也就是1(主版本号).0(次版本号).0(修订版本号)这样的模式。有破坏性的更新动第一位,有新功能动第二位,改改bug动第三位。大部分的开源项目都遵循这个规范,所以我们尽量不要随心所欲的动我们的版本号。当你完成了一个版本,但是对版本的更新内容心里没底的时候,记得先发alpha版本,进行生产上的反复测试。对于已经有很大用户量的项目,应该每次更新都有着alpha, beta, rc乃至更多的先行版本,来给正式版本提供可靠性保障。

文档部署

文档部署在哪里是一个问题,对于大部分的人来说,可能没有精力去维护一个静态服务器。这里我推荐gitee pagesgithub pages,它们可以帮我们托管静态资源,并且是免费的。

截屏2021-09-22 上午12.41.29.png

Git Actions 自动部署和测试

当项目的贡献者越来越多时,一些贡献者不可避免会犯一些流程错误。比如提交代码时忘记跑单元测试,没有尝试对项目进行生产模式的构建等等,为了避免错误,我们需要在提交代码到git远程仓库时去做一些流程性的任务,也就是我们常说的ci/cd或者流水线。又比如说每次发布新版本,不可避免的需要对文档进行重新部署,每次都手动部署也太麻烦了,这种流程性的任务也可以解决我们的问题。 Git Actions可以很好的解决我们的问题,我们可以让它帮我们执行单元测试和代码校验,帮我们做githubgitee的同步,帮我们做文档的部署,解放我们的双手,减少错误的发生。

截屏2021-09-22 上午12.33.35.png

PR,ISSUE规范

做一个开源项目一定会收到许多prissue,但是很多人并不清楚仓库所有者最需要的信息是什么,为了更快的定位bug和解决问题,可以在github仓库提供prissue的模板来解决这一问题。也可以提供贡献指南或者开发手册,让有兴趣的人更快的可以参与进来。

截屏2021-09-22 上午12.46.50.png

写在最后,并感谢贡献

Varlet在去年十月份左右写下第一行代码,第二年的五月份左右发布了1.0.0版本。开发成员全是有着自己全职工作的年轻人,白天上班,晚上肝,完全是兴趣驱动。慢慢社区中也有一些伙伴加入进来,我们认识了许多的朋友,偶尔拉拉家常,点点奶茶云聚餐,可能这就是开源的乐趣所在,自由,并且人人都可以参与,人人都可以分享。偶尔得到他人的肯定,肯定你这件事做的还不错,会让大家十分开心。感谢以下小伙伴们的贡献,以后我们继续加油,继续快乐的写代码,也希望看到这的朋友们,乐于参与开源,积极分享自己的东西。

截屏2021-09-21 下午11.50.56.png