git前端工程实现ci_大前端项目代码重用,也许lerna是最好的选择

我前段时间参与了一个react为主的大前端项目,覆盖Web、Android、Ios三个平台。由于整个业务逻辑侧重在手机端,且Web端也是到了项目中期才开始启动,我在搭底层框架时就没有考虑用类似react-native-web这样的框架把三端统一,而是分别以react-native和react为主起了两个项目来应对。

由于无论哪一端,调用的后端微服务集群都是同一个,导致两个项目中还是不可避免的出现了一些重复逻辑,我尝试了封装成npm包来重用逻辑,但仅限于那些通用且变化较少工具类代码,对于变化频繁的业务逻辑代码,封装出来的npm包时不时就要更新版本,且抽出到项目之外也不易开发和调试,用起来格外麻烦,得不偿失。

最近尝试了lerna,惊喜的发现它不但能解决当时项目的痛点,还能额外带来一些多项目管理相关的好处。

引入lerna

lerna的名字来源于希腊神话中的九头蛇海德拉(Lernaean Hydra),拿它形容多项目工程是再贴切不过了。

lerna的引入比想象中简单,其实,与其说引入lerna,倒不如说是导入到lerna更合适,因为具体的做法是通过命令行创建了一个新的lerna项目,然后把所有项目导入进去。而且在导入的同时,每个项目的git提交记录也都合并在了一起。

lerna initlerna import 你本地的项目路径

每个被导入的项目都会被存放在根路径的packages目录下,下面是我demo项目的截图,一共引入了三个子项目,分别是:rntest, web-app, shared。

17d68756134f3f768ffd3e866adc7fe4.png

使用lerna来管理项目依赖

引入lerna后,第一件事就是要处理安装依赖的问题,我们需要用lerna add 命令来代替我们习惯的npm或yarn,比如说现在给截图中的rntest项目安装lodash,就要执行下面的命令,该命令的底层实现也还是调用哦npm install之类的命令。

lerna add lodash --scope=rntest

不过,执行后你会发现其他项目中package-lock.json都发生了变化,让人非常困惑,这背后的原因是跟添加依赖后自动执行的安装命令lerna bootstrap有关。

ae420cbe1a0d2ac0bb13edd4c8711d26.png

lerna的依赖提升

lerna可以通过lerna bootstrap一行命令安装所有子项目的依赖包,而且在安装依赖时还有依赖提升功能,所谓“依赖提升”,就是把所有项目npm依赖文件都提升到根目录下,这样能避免相同依赖包在不同项目安装多次。比如多个项目都用了redux,通过依赖提升,只需要下载一次放到根目录的node_modules目录下,就可供其他所有项目来使用。不过,需要额外的参数--hoist让依赖提升生效。

lerna bootstrap --hoist

但是自动执行lerna bootstrap命令是不带依赖提升参数的,这就导致上面每个项目的lock文件都会被修改的原因。

当然,要解决这个问题也容易,可以通过lerna的配置来避免npm对lock文件的修改即可,写法如下:

b544e0634248c5208ce28a4ff9fc6e61.png

yarn是lerna的最佳搭档

lerna默认使用npm作为安装依赖包工具,但也可以选择其他工具。yarn在1.0版本之后提供了workspaces的功能,该功能从更底层的地方提供了依赖提升,做的事情跟lerna如出一辙。把它跟lerna放在一起看,简直就像是为lerna量身定做一样。因此,推荐在lerna中搭配yarn一起使用。

把npm替换成yarn只需在lerna的配置文件添加两行代码即可,配置完以后立刻顺畅百倍。

0fa94233a0ebcc06555fa481855a6750.png

高效的代码重用

在我参与的这个大前端项目里,多端之间代码重复的部分包含redux中的业务逻辑、http请求的处理、代码规范工具的检查、git钩子中的自定义脚本等等。在lerna架构下,前两者可直接抽取到一个独立的项目,然后被其他项目引用,比如在我的demo中,可以像其他依赖包一样直接引入shared项目, lerna会自动识别并把它导向内部项目。

import shared from 'shared'

这跟直接封装成npm包的一大区别就是实时更新,修改立刻可见,就像在同一个项目一样,不影响开发和调试。

git钩子和自定义脚本的重用

我尝试把处理git钩子的工具husky安装到了根目录,触发的事件和自定义脚本能覆盖到每个项目,给这部分代码重用带来了极大便利。比如,不少项目会添加自定义脚本来约束git commit提交时的消息描述,在lerna架构下,只需写一次即可。

eslint的重用

那些常常需要在根目录添加配置文件的第三方依赖,比如eslint、prettier、babel等,在lerna中无法简单粗暴的提升合并到一处。因此,对于eslint这种前端开发已不可或缺的工具,可以尝试将所有配置项抽取到独立项目,然后安装第三方依赖的方式引入,类似eslint-config-airbnb,eslint-config-prettier,eslint-config-google这样。

不得不说,即便不用lerna框架我们也可以这么做,只不过在`lerna`框架下修改立刻可见,方便了调试和开发。

lerna框架下的CI/CD

多项目的结构无疑给CI/CD带来挑战,好在主流的CI框架能完美解决这个问题。比如在gitlab上,only/changes参数完全满足了我们的需求,让我们可以为每一个子项目设置单独的pipeline,比如现在我们设置一个pipeline,只当rntest项目下的文件被修改时才会触发:

d247b4465ad9cd03b2d63bc6f4e5e32f.png

在lerna框架下,所有项目都合在一个工程里,但CI/CD并不必这样。通过把脚本中的关键参数配置到CI/CD的项目内里,共用同一份.gitlab-ci.yml文件,从而能够实现每个子项目对应一个独立的CI/CD项目,最终CI/CD结构如下图:

3eb6a0e7fb74b8e6fac664ba70671bed.png

lerna框架下的子项目权限

由于所有的项目都归并到了一个lerna工程下,一旦有了访问权限意味着你可以修改所有子项目中的代码,在实际的开发工作中多多少少会带来一些麻烦。比如说,开发web和开发mobile平台的是两个不同的团队,假如我作为web组的一员,一不小心修改了或删除了mobile项目的文件该怎么办?假如不加入任何限制,这种事情迟早会发生,我想这可能是lerna框架与生俱来的的痛点。

不幸的是,在lerna框架下,gitlab或github这类第三方代码托管平台,本身的权限管理功能无法解决这问题。但好在有其他工具的帮助可以缓解这种痛,我尝试用来约束开源贡献者提交PR规范的工具dangerjs来完成权限分隔,利用的信息就是当前gitlab账号的用户名,看起来效果还不错。

46ebe64a85d493aed93694ab72d3adc2.png

可以看到,此工具会在合并MR时,判断出我gitlab账号没有权限修改rntest子项目内的文件,从而禁止合并此MR,并将这些信息自动添加到MR的评论里。当然,脚本判断是自己写的仅用作演示,逻辑比较简陋,脚本代码如下:

4faa129cbc9bee41fb93fc020f2508ec.png

关于dangerjs的部分我会另写一篇文章详细介绍。

结语

大前端项目将会是前端发展的趋势,如何更好的管理大前端项目是每一位前端开发躲不开的课题。lerna框架通过合而为一的理念提供了一种解决方案,通过扬长避短,我们可以发挥出lerna的最大效用。假如你还没有用过,也许,下一个项目就可以试试看。

参考资料

  • https://github.com/lerna/lerna
  • https://gitlab.com/twomeetings/lerna-demo (文章中的demo)
  • https://classic.yarnpkg.com/en/docs/workspaces/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值