在聊模块联邦之前,我们先了解下在多个项目下,前端模块如何复用的
跨项目模块复用方案
1、npm 包
包管理工具对于前端应用来说不可或缺,我们可以将模块上传到 npm 包,在需要的项目中引入,以此来复用一些公用模块。
2、monorepo
monorepo
是一种将多个项目代码存放在一个仓库里的软件开发模式,monorepo 中所有的项目相互独立,但不同项目之间可以相互引用
3、git submodule
git 提供了子模块做代码复用,任何一个git repo 都可以通过引用其它 repo(子模块)来做模块复用,在主项目中通过git commitid
来管理子项目的版本。这就带来一个问题,多人协作中子项目版本容易造成冲突,每次都需要手动更新子模块引用,子模块版本管理很难做
4、复制粘贴
CV大法 或许是实现复用成本最低的一种方案,github有过一项统计,其托管的项目代码有一半是重复的。虽然复制粘贴能够快速实现代码复用,但是对于未来的长期维护却是灾难性的,代码维护成本会越来越高
5、 UMD
UMD
是 (Universal Module Definition) 通用模块定义的缩写,UMD 将 commonjs、amd 规范集于一身,并支持导出全局变量使用。UMD
方案存在一些缺陷:其导出的全局变量,容易造成冲突,而且多个 UMD 模块如果相互依赖,那么加载顺序就需要手动去维护,tree shaking
也不是很好做
我们刚才提到的跨项目模块复用的方案中,除了UMD
方案,其它4种,最大的局限是复用组件、项目升级后,需要所有依赖它的项目进行升级、编译、上线,一两个项目这么做可能没什么问题,但是如果是几十个项目,就显的过于繁琐
有没有一种方案,复用模块版本升级,所有依赖它的项目不再需要单独部署上线,在线上环境就能加载到升级之后的模块?
webpack5 提供了模块联邦,解决了上述问题,让代码直接在项目间利用 CDN 直接共享(远程模块),不再需要本地安装 npm 包、构建在发布了
模块联邦概述
下面是官网的介绍:
多个独立的构建可以形成一个应用程序。这些独立的构建不会相互依赖,可以独立开发、部署,这通常被称为微前端,但并不仅限于此。
模块联邦中有几个重要的概念
Remote
作为模块提供者,对外导出模块,被 Host 引用
Host
作为模块消费者,可以动态加载 Remote 提供的模块
Share
Remote、Host可以共享相同的依赖,避免重复打包,减少包体积
下面这张图可以清晰的看到他们三者之间的关系
如何使用
webpack5 提供了 ModuleFederationPlugin
插件来使用模块联邦,下面是插件的配置项
Remote 配置
new ModuleFederationPlugin({
name: "component_app",
filename: "remoteEntry.js",
exposes: {
"./Button":"./src/Button.jsx",
},
shared: ["react", "react-dom"]
})
name
是模块名称,用来标识模块,以确保其它模块能够正确引用该模块
filename
用于指定输出模块的文件名,其它项目通过其加载导出的模块
exposes
用来指定需要导出的模块
shared
用来指定需要共享的依赖模块,如果两个应用都使用了相同的依赖,则可以使用 shared 来共享依赖,减小打包体积
Host 配置
new ModuleFederationPlugin({
name: "main_app",
remotes: {
"component-app":"remote_url"
},
shared: ["react", "react-dom"]
})
关于Host
,重点说一下 remotes
配置
它是用来指定需要从哪个应用加载远程模块,其中 component-app
是一个模块别名, remote_url
是 Remote 导出的 filename
文件地址
在项目中引入共享模块 Button
(以上面 Remote 导出的模块为例,在 Host 项目中使用),由于是异步模块,所以需要使用 import()
来引用
React.lazy(() => import('component-app/Button'))
如果是多个项目,每个项目配置Host
后,即可方便的使用 Remote
导出的模块 Button,这样如果Button 组件修改,我们只需要单独打包 Button 所在的 Remote
应用,重新导出最新的 Button 模块后发布,其它项目中引用的 Button 模块就是最新发布后的代码了,不再需要单独构建、发布了
优点
1、配置简单灵活
2、支持独立部署,上线
3、运行时加载模块,以及共享依赖,减少应用包体积
4、相比 externals 以及 dll
,模块联邦能够更好的做到按需热插拔
缺点
1、必须使用 webpack5
2、模块联邦对runtime
运行时做了大量改造,在运行时要做的事情也因此增加很多,会对我们页面的运行时性能造成一定的负面影响
3、由于是运行时共享,那么远程模块的版本管理也是应该去考虑的问题
参考链接
社区中 webpack4 支持模块联邦的 (https://github.com/module-federation/webpack-4)
脱离 webpack 技术栈,支持模块联邦的也有 (https://github.com/tnfe/hel)
- END -
关于奇舞团
奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。