模块联邦
模块共享之痛
对于一个互联网产品来说,一般会有不同的细分应用,比如腾讯文档可以分为word、excel、ppt等等品类,抖音 PC 站点可以分为短视频站点、直播站点、搜索站点等子站点,而每个子站又彼此独立,可能由不同的开发团队进行单独的开发和维护,看似没有什么问题,但实际上会经常遇到一些模块共享的问题,也就是说不同应用中总会有一些共享的代码,比如公共组件、公共工具函数、公共第三方依赖等等。对于这些共享的代码,除了通过简单的复制粘贴,还有没有更好的复用手段?
复用手段历史解决方案,主要包括
发布 npm 包、Git Submodule、依赖外部化 + CDN 导入和Monorepo 架构
发布 npm 包
发布 npm 包是一种常见的复用模块的做法,我们可以将一些公用的代码封装为一个 npm 包
封装 npm 包可以解决模块复用的问题,但它本身又引入了新的问题:
-
开发效率问题。每次改动都需要发版,并所有相关的应用安装新依赖,流程比较复杂
-
项目构建问题。引入了公共库之后,公共库的代码都需要打包到项目最后的产物后,导致产物体积偏大,构建速度相对较慢
因此,这种方案并不能作为最终方案
Git Submodule
submodule允许你将一个Git 仓库当作另外一个Git 仓库的子目录
通过 git submodule 的方式,我们可以将代码封装成一个公共的 Git 仓库,然后复用到不同的应用中,但也需要经历如下的步骤
- 公共库 lib1 改动,提交到 Git 远程仓库;
- 所有的应用通过
git submodule命令更新子仓库代码,并进行联调
整体的流程其实跟发 npm 包相差无几,仍然存在 npm 包方案所存在的各种问题。
缺点:
- cicd持续集成的时候,需要注意的是, 需要拉去最新的子仓库的代码
- 更新子仓库代码时候,每个应用都需要更新子仓库
Monorepo
作为一种新的项目管理方式,Monorepo 也可以很好地解决模块复用的问题。在 Monorepo 架构下,多个项目可以放在同一个 Git 仓库中,各个互相依赖的子项目通过软链的方式进行调试,代码复用显得非常方便,如果有依赖的代码变动,那么用到这个依赖的项目当中会立马感知到
缺点:
- 所有的应用代码必须放到同一个仓库。如果是旧有项目,并且每个应用使用一个 Git 仓库的情况,那么使用 Monorepo 之后项目架构调整会比较大,也就是说改造成本会相对比较高。
- Monorepo 本身也存在一些天然的局限性,如项目数量多起来之后依赖安装时间会很久、项目整体构建时间会变长等等,我们也需要去解决这些局限性所带来的的开发效率问题。而这项工作一般需要投入专业的人去解决,如果没有足够的人员投入或者基建的保证,Monorepo 可能并不是一个很好的选择。
- 项目构建问题。跟
发 npm 包的方案一样,所有的公共代码都需要进入项目的构建流程中,产物体积还是会偏大
vite模块联邦
- vite-plugin-federation 插件,这是社区提供了一个比较成熟的vite模块联邦方案
- 支持vite/rollup
使用
- 使用Module Federation通常需要2个以上的工程,一个作为Host端【本地端】,一个作为Remote端 【远程端】
需要注册配置 远程模块和本地模块
模块联邦实现
实现模块联邦的三大主要:
Host模块: 即本地模块,用来消费远程模块。Remote模块: 即远程模块,用来生产一些模块,并暴露运行时容器供本地模块消费。Shared依赖: 即共享依赖,用来在本地模块和远程模块中实现第三方依赖的共享