热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

大前端项目代码重用,也许lerna是最好的选择

我前段时间参与了一个react为主的大前端项目,覆盖Web、Android、Ios三个平台。由于整个业务逻辑侧重在手机端,且Web端也是到了项目中期才开始启动,我在搭底层框架时就没



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


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


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


引入lerna


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


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


lerna init
lerna import 你本地的项目路径

每个被导入的项目都会被存放在根路径的packages目录下,下面是我demo项目的截图。



使用lerna来管理项目依赖


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


lerna add lodash --scope=rntest

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



lerna的依赖提升


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


lerna bootstrap --hoist

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


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



yarn是lerna的最佳搭档


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


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



高效的代码重用


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


import shared from 'shared'

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


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


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


eslint的重用


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


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


lerna框架下的CI/CD


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



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



lerna框架下的子项目权限


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


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



这个工具会在合并MR的时候,判断出我gitlab账号没有权限修改rntest子项目内的文件,因此禁止合并此MR,并将这些信息自动添加到MR的评论里。当然,脚本判断的逻辑比较简陋,仅用来做演示用,而关于 dangerjs 的部分我会另写一篇文章详细介绍。


结语


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



相关资料

lerna的github地址


文章中的demo






推荐阅读
author-avatar
一个人的靓靓_523
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有