前端 Monorepo 实践(Monorepo使用)
什么是 Monorepo
作为前端工作者,可能听说过微前端,也听说过 Monorepo。有时候我们会混为一谈。
简单的说,微前端是「聚」,Monorepo 是「分」。
微前端解决的问题是,将多个以不同技术完成,但是拥有相同业务逻辑的 app 聚合到一起。而 Monorepo 却相反,是将一个 app 中相对比较独立的逻辑,拆分成独立的 package,减少相互的耦合和制约,并且使用同一个 Repo。
Monorepo 和普通 Repo 的关系
通常情况下,我们会在一个 Repo 下使用一个 package。类似如下的项目结构。
src -feature1 -feature2 -feature3 -feature4 package.json复制代码
这样的项目结构在项目还比较小的情况下还好。但是随着项目的不断扩大,就会出现一些弊端:
项目越来越大,每一次很小的改动都会影响整个项目。(build 时间长,或者业务逻辑的影响)
业务逻辑直接的耦合,无法拆分清楚。
可能会多个 team 维护一个 Repo,team 直接也不好合作。
不同的业务逻辑可能希望分开发布来避免互相影响。
解决方法当然是 Monorepo,我们看一下 Monorepo 的项目结构:
projects -feature1 -src -package.json -feature2 -src -package.json -feature3 -src -package.json package.json复制代码
对应相面的问题,我们来看一看 Monorepo 的优势:
项目上功能的增加,转换为子 package 的增加,每一个独立的功能也只需要关心自己当前的 package 即可。(包括编译)
因为 package 之间的隔绝,需要我们将 package 直接的依赖关系理清楚。业务逻辑的依赖关系转换为了 package 直接的依赖关系,更为清晰。
每个 team 维护自己的 package 就可以的。甚至可以指定属于自己的编码规范,lint,build,都可以自己做自己的配置。
按照 build 分开 deploy 即可。
Monorepo 需要解决的问题
每个 package 的依赖如何避免重复安装。比如一个 Angular 项目,每个 package 可能都需要安装 angular,如何避免不同 package 重复安装。
相同 Repo 下不同 package 直接依赖如何处理。
单 package 下我们可以简单的使用,npm script 处理各种问题,在多 package 下我们该如何使用?
下面我们来看看常用的几种解决方案:
方案一,Angular 默认的解决方案:
利用 node 的向上查找策略,将所有依赖收敛到根 package。package 内只安装自己独有的依赖。
使用 npm link 或者 tsconfig 中的 path,将编译后的目录连接到每个项目。
Angular 通过 angular cli 提供。
方案二,Lerna + yarn workspaces
Lerna 提供的 lerna add xxx --scope=xxxxx 来安装依赖。
lerna add 同时支持,安装当前项目的其他 package,如果本地存在当前版本,优先加载本地(类似 npm link),如果本地不存在则从远端加载。
lerna 可以在任意 folder 执行,加上,--scope 即是某个 package。Lerna 还集成了一系列其他常用的命令。
lerna clean 清除所有的 node_modules
lerna bootstrap install all packages
lerna version
以上两种方案其实并不算完美:
如果每一个 package 的依赖都互相独立,则可能出现同一个 repo 下对于相同依赖的多次安装,不仅会增加项目的体积,也会因为相同项目对于同一个依赖的不同引用出现使用上的问题。Node 中的 node_module hell 也会因为 Monorepo 而成倍的放大。
如果项目中的多数依赖都放在 package 中,则会导致每个 package 的依赖不够清晰(Angular 推荐使用,peerdependency 的折中方案)。假设某一天,我希望将某一个 package 独立成一个 repo,发现,很难写清楚,这个 package 真实的依赖有哪些。
内部项目的依赖关系仍然没有办法指定清楚。
方案三:pnpm
归根结底,以上问题还是因为包管理工具不够强大。pnpm 的出现,是为了解决,node_modules 打平的问题而出现的。
pnpm 的出现,使得,子 package 可以像一个独立的 app 一样去指定自己的依赖。
pnpm install xxx --filter=xxxxx
,因为 pnpm 中 node_module 会 link 到 pnpm 的根目录,所以,完全不用担心,同一个 package 在不同子 package 的重复安装。pnpm 提供了
workspace*
来制定当前项目的 package,*
会在pnpm publish
前替换成真实的版本号。pnpm 提供了一系列支持 monorepo 的命令可以让我们减少使用 lerna.
作者:Lian Shenghua
链接:https://juejin.cn/post/7036016254385127431
伪原创工具 SEO网站优化 https://www.237it.com/