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