Skip to content

开源初体验

🕒 Published at:

由于项目上的任务并不很重,于是我在闲暇之时看起了 element-plus 的源码,不得不说,ep 在项目工程化的设计上显得非常出色。vscode 有一个功能,当点击某一行代码的时候,下面状态栏会显示这行代码是谁 commit 的,ep 的强大离不开众多开源爱好者的支持,所以每切换一行代码,都能看到不同的作者。

一颗种子,从此刻开始生根发芽

当时的我在想:如果我也能和全世界的开源爱好者共同开发一个项目,那将是多么自豪的一件事啊!

公司之前的项目上一直遗留着一个问题,由于用到了 ep 的穿梭框组件,但是渲染了大量数据下会变得卡顿,其根本原因还是 ep 的 transfer 不支持虚拟滚动优化,所以就套用了 naive-ui 来应付这个需求。

于是,我开始挑战自己,尝试一把看能不能自己动手,丰衣足食。

成长的路上,总是充满艰难坎坷

element-plus 的源码我之前也看过过一点,但是不多,在做公司二期项目的时候来借鉴了 ep 的整体工程化架构。

我最开始接触 ep 源码的时候也是一脸懵逼的,不知道从哪开始下手,只在那里盲目的翻来翻去,这种状态持续了很长一段时间,直到某一天静下心来慢慢研究其构建逻辑,然后观察 package/ 下的模块,才对整个项目有了大致的理解。

ep 是一个完完全全标准的 monorepo 项目,每个模块,包括 css、i18n 都分的清清楚楚,但是缺点就是组件多起来之后项目会变得非常庞大,IDE 解析 TypeScript 的时间会变得更长。好在,ep 提供了 play 模块来供开发者进行调试(我也借鉴了这个 play 的模块管理模式,将二期项目的 shared 包优化了一遍,使其支持了 hmr),我将复现代码贴在了 play 上,然后定位到了组件源码位置,开始逐步了解 transfer 的组件设计方式。

transfer 组件通过复用子组件 transfer-panel 来实现数据穿梭显示,组件整体逻辑并不复杂,卡顿的核心原因还是组件直接 v-forel-checkbox。那么,优化的思路自然而然的就来了:给其加个参数,开启虚拟滚动就可以了。

当然,参数也不是说加就加的,ep 有一套极为严格的开发规范,每个参数都规范管理,都会加上和文档一致的注释说明。不过上手还算简单,参考已有的参数,直接 copy 一下改一改堆上去即可。

既然参数加上了,那么就开始着手实际优化。ep 内置了虚拟列表组件 FixedSizeList,直接套用上去,然后再 v-if 一下即可。很快,我就在开发环境完善了这个功能。

打破信息茧房,才会更好的发展自身

于是,我鼓起了勇气,向 element-plus 提出了我第一个 PR。

然而,等待我的并不是被合并的喜报,而是一堆代码审查意见。ep 源码仓库引入了 codexcoderabbit 两个 AI 工具来协助审查以及一堆自动化工具链来打包发布,整个“生态链”显得特别完美。

首先是两位“AI 老师”的审查,由于我新加的参数没有按照规范来,需要进行进一步修改,比如驼峰命名规范、文档同步等。我再一次修改并进行了 commit。

接下来是 ep 的一位成员(暂且称他为“成员 A”吧)对我提交的代码进行了审查,告诉我没有在文档上面加上版本标签,我又一次修改并进行了 commit,可以看出来,ep 对于文档的严谨性有多高。

版本规范了,“成员 A”反馈给我需要加上一些测试用例,ep 使用了 vitest 进行单元测试,我之前也没怎么接触过这种,但是还好,借鉴已有的测试用例,我也对其进行了完善。

“成员 A”看着应该没问题了,便请求了另外三个团队成员“成员 B”、“成员 C”和“成员 D”来审查。

“成员 B”通过 ep 自建的一个 playground 来复测了一遍,发现参数并未生效,我也挺纳闷,便亲手试验了一遍,果然如此。回去重新排查了一下,发现开发环境是正常的,但是打包之后就不行了,问题出在了参数上面。组件在声明参数的时候,有一个地方没注意:ep 通过 export interface TransferProps<...> 来声明 transfer 的参数,而往下翻代码会发现,还有一个 export const transferProps = buildProps({...}) 来声明参数,但是这个方法上面打上了一个 @deprecated 标签,说是要在 3.0.0 后移除这个方式。当完善这个方式里面的参数后,再一次进行打包测试,终于修复了这个致命的问题。

接下来到了“成员 C”审查,“成员 C”又指出了两个问题:一个是组件命名方式问题,需要和其他组件一样,保持 kebab-case 的方式来书写;第二个则是在 transfer 启用筛选功能时,虚拟列表需重置滚动。于是,我再一次修改并 commit 了代码。

最后来到了“成员 D”来审查,又给了我一个审查意见:由于虚拟列表在重置滚动的时候,需要等待 DOM 更新才可以进行,我在 watch 里面套用了 nextTick,其实可以给 watch 加一个 { flush: 'post' } 来简化这一逻辑(我之前不知道有这个方法),我不知道这是第几次修改了,再一次进行了 commit。

当被认可的那一刻,所有付出都是值得的

终于,当我看到我发起的 PR 被合并的那一刻,那种发自内心的自豪感是无法用言语上表达的。

通过这次尝试,我发现 element-plus 之所以强大并且能够长期维护下去,和一系列严格的开发规范息息相关,就比如驼峰命名、prop 逻辑、Code Review 流程等,都是一次次尝试,一次次跌倒了又爬起来的经验之谈。

其次,由于 ep 是全球的开源爱好者在共同维护,交流普遍是使用英语,包括每次 commit、每次 Code Review 以及文档内容都是使用英语来书写,我个人的英语基础并不是很好,在这次 PR 中大部分情况都是借助翻译软件来交流,看来想要长久发展下去,学好英语也是一件很重要的事情。

最后,这次 PR 给我带来的经验虽比不上大厂,但胜似大厂。毕竟据我了解,这次的整个流程已经是一个很完善的大厂内部规范了。曾经我以为 Code Review 是在挑刺,但通过这次的经历让我意识到:真正优秀的项目并不是因为代码写得多完美,而是每一行代码都经历了无数次的推敲和讨论。而这也是我这次开源经历中最大的收获。

附:PR 链接