我前段时间参加了一个react
为主的大前端我的项目,笼罩Web、Android、Ios三个平台。因为整个业务逻辑偏重在手机端,且Web端也是到了我的项目中期才开始启动,我在搭底层框架时就没有思考用相似react-native-web
这样的框架把三端对立,而是别离以react-native
和react
为主起了两个我的项目来应答。
因为无论哪一端,调用的后端微服务集群都是同一个,导致两个我的项目中还是不可避免的呈现了一些反复逻辑,我尝试了封装成npm
包来重用逻辑,但仅限于哪些通用且变动较少工具类代码,对于变动频繁的业务逻辑代码,封装进去的npm
包时不时就要更新版本,且抽出到我的项目之外也不易开发和调试,用起来分外麻烦,得失相当。
最近尝试了lerna
,惊喜的发现它岂但能解决过后我的项目的痛点,还能额定带来一些多项目管理相干的益处。
引入lerna
lerna
的名字来源于希腊神话中的九头蛇海德拉(Lernaean Hydra),长相可参考我的项目logo,拿它形容多我的项目工程是再贴切不过了。
lerna
的引入比设想中简略,其实,与其说引入lerna
,倒不如说是导入到lerna
更适合,因为具体的做法是通过命令行创立了一个新的lerna
我的项目,而后把所有我的项目导入进去。而且在导入的同时,每个我的项目的git提交记录也都合并在了一起。
lerna initlerna import 你本地的我的项目门路
每个被导入的我的项目都会被寄存在根门路的packages目录下,上面是我demo我的项目的截图。
应用lerna来治理我的项目依赖
引入lerna
后,第一件事就是要解决装置依赖的问题,咱们须要用lerna add
命令来代替咱们习惯的npm
或yarn
,比如说当初给截图中的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的重用
那些经常须要在根目录增加配置文件的第三方依赖,比方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我的项目下的文件被批改时才会触发:
在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