写在前面
掘金的同学们大家好呀,我是 Vue3 移动端组件库 Varlet UI 的作者,时间过的真的很快,转眼已经来到了 2023 年的 10 月,上一次梳理和分享组件库的架构还是在两年以前 Varlet
刚刚开源的时候,承蒙社区同学们的帮助,两年过去之后 Varlet
已经有了 4000+ 的 star 数量。
在两年前作者曾写过一篇 如何从0到1开发一个开源组件库 希望能够分享和记录组件库从 0 到 1 的心得和思考,同时也希望社区对组件库有兴趣的同学们可以少走一些弯路。然而时至今日前端的生态已经有了翻天覆地的变化,Varlet
也不断的学习并且紧紧追赶,同时也有了长足的进步。本篇文章作者将以一个组件库作者的视角来分享一下目前 Varlet
组件库的架构变化和思路。
Pnpm Monorepo 拆包架构
Monorepo 的好处在于可以将项目中通用的部分单独抽离成一个包进行单独的发布和管理,并且免去了很多依赖关系的维护压力。这有利于组件库的生态建设,我们在项目初期就采用了这种架构,当时采用的是 yarn workspace + lerna
的方式。之后 pnpm 大行其道,我们快速的切换到了 pnpm,pnpm 性能更好并且更加节省磁盘空间,并且对于依赖关系有着更优秀的处理,并且有效的解决了幽灵依赖对于项目整体产生的影响。
目前的拆包结构如下...
lua
|-- packages
|-- varlet-cli 组件库命令行工具,管理整个组件库的生命周期
|-- varlet-eslint-config 组件库的 eslint 规则
|-- varlet-icons 组件库图标库打包工具
|-- varlet-shared 共享的通用工具
|-- varlet-touch-emulator 桌面端适配器
|-- varlet-ui 组件库本体
|-- varlet-ui-playground 组件库的演练场,在线编辑工具
|-- varlet-use 组件库用到的 composition api
|-- varlet-vite-plugins 组件库依赖的 vite 插件
|-- varlet-vscode-extension 为了提高开发体验的 vscode 插件
Design System 设计系统
设计系统和设计资源对于组件库来说十分的重要,也是连接设计师和软件开发工程师的桥梁。没有设计系统,我们的组件将失去标准和原则,将失去一致性 ,最后的视觉效果也会大打折扣。 没有设计资源,设计师就很难配合软件开发工程师行之有效的产出软件设计稿,组件库就很难真正的落地到产品中去。
建议在有条件的情况下先完成设计稿再进行组件实现。我们起初先完成的组件功能后补的设计资源,吃了很大的亏。 在后期又单独花精力对所有组件的视觉重新进行了一次修正,费时费力,并且产生了一些破坏性变更,实在是得不偿失。
而且同学们不需要对做设计图有畏难情绪,像是 sketch figma 之类的工具很符合我们前端开发的惯性思维,非常容易上手。
组件编写风格 SFC OR TSX
我们采取了 SFC 和 TSX 互补使用的组件编写风格,主要使用 SFC,因为 Vue 的 SFC 编译器提供了许多的编译时优化,在运行时性能更好。TSX 用于弥补 SFC 的一些开发短板 (比如对于 VNode 的操作 SFC 没有 TSX 方便),各取所长。
开发环境拥抱 Vite 生态
我们的开发环境由 Webpack5 迁移到了 Vite,并且将项目所需的 Vite 插件独立成了一个包。Vite 很好很强大,既可以用做开发服务器又可以用作库编译器,对于自建组件库文档来说是不二之选。同时也很期待 Vite 之后可能出现的基于 Rust 的构建工具 Rolldown。总的来说,Vite 是一个充满可能性的技术,值得我们拥抱它。
图标库
我们采用的方案是传统的字体图标方案,这种方案使用起来十分方便,我们使用 varlet-icons 把 svg 图片集打包成字体文件和 css 以供组件库使用。
Vitest 单元测试
我们的单元测试工具从 jest 迁移到了 Vitest, jest 一个众所周知的问题就是配置文件比较多,需要单独配置编译相关的东西,这些东西实际上 Vite 早就帮助我们处理好了。Vitest 的最大优势就是和 Vite 共享配置,可以减少很多依赖和配置的维护负担。
并且 Vitest 对测试文件的执行速度也有了极大提升,在 Mac M1 上尤为明显。不过 Vitest 显然在单核 cpu 上速度就没有那么快了,CI 上的速度和 jest 可以勉强五五开。迁移到 Vitest 还是很值得的。
基于原生语言的 JS/TS 编译器
随着基于原生语言的 JS/TS 编译器大热,社区中涌现出许多的基于原生语言的编译器的上游工具可供我们替换一些旧的工具。浏览器场景
的 TS 库的编译器我们选择使用 tsup 替换 Typescript 的官方编译器 tsc,tsup
是基于 esbuild 的,它的编译速度是 tsc
的很多倍,并且足够的开箱即用。
Node 场景
的 TS 库,我们推荐使用 unbuild,它在开发模式下提供了一个 typescript
的运行时,可以免去 watch
文件进行重复编译的性能开销,同时也支持生产环境的构建。我们最后没有采用它的原因是因为不太希望项目中的编译器太过冗杂,并且对于我们来说 Node 场景
的 TS 库也是不多的。最终选用 tsup
对除组件编译之外的所有场景的库进行编译。
我们对组件的编译是通过自研的编译器进行的,自研编译器的好处在于编译流程足够可控和直接,并且足够的轻量,编译核心也从 babel
过度到了 babel
+ esbuild
的混合编译方式,使用 babel
去处理 vue jsx语法
, 再用 esbuild
进行编译和语法降级,极大的加快了编译速度。
编译产物
为了满足不同场景的使用需要,一般情况下我们需要以下几种产物,esm
、cjs
、umd
。 esm
一般用于构建工具的场景,cjs
一般用于较老旧 node 版本的服务端渲染和单元测试场景、umd
一般用于浏览器 cdn 方式引入的场景。我们通过自研的组件编译器按照目录结构输出 esm
模块,按照目录结构输出对组件按需引入更加友好,再通过 Vite 的库编译模式输出 cjs
和 umd
的捆绑文件。
文档的部署
本着能不花钱就不花钱的原则,国内首选 Gitee Pages 服务,国外首选 Vercel。部署两个站点有利于国内外用户的访问体验。Vercel 还有一个优势在于可以直接通过 github app 集成到 CI,每个 pr 或者 commit 都可以自动的部署并得到一个可访问的地址,有助于你对每个提交对应的组件效果有一个清晰的预览和了解,毕竟我们做的是组件库,视觉效果的审查是极其重要的。
演练场
每个组件库都需要一个在线的编辑工具,以便用户反馈、复现 bug 或是提出问题,我们魔改了 Vue 官方的 playground 代码,构建了一个 Varlet Playground,具体实现细节可以查看这篇文章 Vue3组件在线交互解释器,或者查看源码。 也可以使用一些成熟的服务,如 codesandbox,但是相对 playground
就没有那么轻量,在线构建也比较耗时,国内网络不好的同学访问起来也比较困难。
VSCode 插件
组件库不光需要满足用户体验,还要尽可能的满足开发者的使用体验,VSCode 插件是一个很好的入手点。 我们尝试开发了一个 VSCode 插件。功能如下
- 🛠️ 支持全组件的语法提示、快速补全。
- 🛠️ 支持全组件的文档地址预览、快速跳转。
- 🛠️ 支持框选代码片段,快速打开
Playground
。 - 🛠️ 支持图标组件的全图标预览。
- 🌍 支持中英文切换。
顺道一提我们还做了一个 varlet 的 vscode 主题
插件可在 VSCode 的插件市场搜索到
感谢大家看到这里
不知道自己写的怎么样,也许能帮助到大家的地方不多,但也希望能给大家一些启发。 再次感谢社区同学们对 Varlet
组件库的支持,欢迎 issue
pr
star
。