5-打造属于你的组件库-【模块联邦】
1. 前言
模块联邦是 Webpack5
的新功能,实现了跨应用的共享模块,在之前我们一般会使用 NPM
的方式去共享模块。
NPM 组件库
- 优势:
比较常用的方式,也便于版本管理,TS支持友好
- 不足:
模块升级,使用了该模块的项目,也需要一起升级才能使用最新的模块
使用 NPM 包方式,就意味着如果 NPM 包升级,那么项目里的使用的包也需要升级,重新构建,而模块联邦可以让模块在项目之间利用 CDN 共享,从此便不需要在项目中本地安装,构建,发布了
那么模块联邦又和传统的 CDN 方式引入有何区别?
CDN/UMD 全局引入
- 优势:
运行时加载,简单规划一下,也可以做到版本控制
- 不足:
TS类型支持不友好
一般是直接引入 script 标签,会一次性加载模块的所有资源
需要考虑依赖加载顺序
这两者在我看来,有些类似,都是从远程加载资源共享,但 模块联邦 可以标识出需要 exposes(导出)
的模块,可以根据你的需求去引入。可以在项目页面中需要的地方再去加载,相比 CDN/UMD
来说更灵活。
2. 个人感受
先简述下结论,真正使用的话,需要考虑
-
模块的 TS 类型共享问题(听说有解决方法,日后在瞅瞅)
-
虽然做到了项目共享,但有些项目需要低版本的模块,这边可能需要开发者做中间层去处理版本问题
-
随意升级模块,如果模块有个没测试出来的隐藏 BUG,有可能导致使用模块的项目炸裂。
3. 模块联邦的使用
模块联邦两个概念: Host(消费者)
和 Remote(被消费)
,同时,每个项目即可以是 Host 也可以是 Remote。其本身只是一个 Webpack
的插件 ModuleFederationPlugin
-
属性
name
: 该模块的名字filename
: 模块编译后生成的入口文件名,如果没设置,会根据name
生成remotes
: 当模块为Host
时使用,用来设置可以被导入的模块exposes
: 当模块为Remote
时使用,用来设置模块中的哪些部分可以被导出给Host
使用shared
: 强制远程Remote
模块使用主模块Host
的依赖项,当主模块没有该依赖项时,会直接使用远程模块自身的依赖
-
使用时遇到的坑
-
使用
HtmlWebpackPlugin
自动导入的js
没有加上type='module'
导致浏览器启动时,ES6 模块导出报错// `HtmlWebpackPlugin` 添加 `chunks` 选项 new HtmlWebpackPlugin({ template: './src/index.html', filename: 'index.html', chunks: ['main.js', 'remote.js'], }) // html模板 那添加自己设置的 `script` 标签解决 <% for (var chunk in htmlWebpackPlugin.options.chunks) { %> <script type="module" type="text/javascript" src="<%=htmlWebpackPlugin.options.chunks[chunk] %>"></script> <% } %>
-
引入远程模块,跨域问题
// webpack.config.js devServer: { port: 4001, headers: { // 利用CORS解决跨域 'Access-Control-Allow-Origin': 'http://localhost:4000', }, }
-
host_app
和remote_app
测试失败,没分析出具体原因,测了好多回网上查了很多解决方法,有说 splitChunk 的,也有说 runtime 的,一个一个试了都没用,QAQ 暂时放弃
webpack + js
的方式去测试,转实vite
的模块联邦
Vite 的模块联邦
1. vite-plugin-federation
Vite 模块联邦 Github 支持模块联邦 的 Vite/Rollup
插件,可以与 Webpack Module Federation
兼容。
# 安装
yarn add @originjs/vite-plugin-federation --dev
2. 使用
配置基本和 Webpack 模块联邦类似, remotes
略微不同,在 vite
里,无需添加 name@
的前缀
export default defineConfig({
plugins: [
// ...otherConfig
federation({
remotes: {
// 这里的 value 不同于 webpack, 没有 name@ 的前缀
remote_vite: 'http://localhost:3333/assets/remoteEntry.js'
}
})
],
build: {
target: 'esnext'
}
})
3. 注意事项
由于 Vite
是按需编译的,所以你在本地测试的时候,开启两个开发环境是没有用的, Host
可以在本地启动,但 Remote
需要先部署在线上。
可为了测试一个项目,就部署,太麻烦了,所以这里可以使用 vite preview
的方式去模拟 Remote 的部署。
// preview 是基于 build 之后的文件的,所以在此之前需要先 build 一次
// 由于是测试项目,我就直接在 script 里增加了 yarn build 的代码。然后用 preview 模拟 3333 端口
"preview": "yarn build & vite preview --port 3333"
完成上述操作,即可打开 Host(可以开发环境开启)
查看效果。。。
为什么 Vite 开启两个开发环境会失效呢?
因为 Vite
按需编译的特性,在开发模式下使用的是 esbuild
的 no-bundle
的特性,在启动时,只需要预编译依赖,随后项目启动,进入 index.html
,随即发起 http
请求获取当前所需的资源。
所以你无法在开发环境下找到 remoteEntry.js
的资源。。个人感觉这个可以优化,期待插件后续更新。
而,当你 build
打包之后,在你的项目下就会有 remoteEntry.js
资源了,那么便可以直接访问 http://localhost:3333/assets/remoteEntry.js
转载自:https://juejin.cn/post/7237531176587313212