我正在参加「掘金·启航计划」
前言
webpack5的module federation(模块联邦) 已趋于稳定, 面对这一“新”特性, 落地项目也该提上日程了.
背景
这次的背景项目是个包含PC网站、运营端、用户端、H5端、用户H5端、其它页面端的多端项目, 基于react16+ant4+redux开发; 下一步规划是微前端; 面对越来越多的跨项目重复组件, 模块联邦可谓是完美解决方案.
原理
webpack官网上面说的很明白了, 各位大佬也做了很多解析, 一句话解释(瞎掰): 模块联邦就是远程异步组件.
动手
关键配置位于webpack的plugins内, 通过引入container内的ModuleFederationPlugin进行配置; 关键配置为name、library、filename、exposes、remotes、shared:
- name: 容器名称
- filename: 容器地址名称
- exposes: 暴露的组件名称
- remotes: 远程容器地址(例:
${name}http://demo.com/${filename}) - shared: 本地与远程容器共享的基础组件(库)
公共配置
const webpack = require("webpack");
const { ModuleFederationPlugin } = webpack.container;
{
...
output: {
publicPath: `/`,
},
}
提供容器配置
- 必须配置name、filename、exposes以供远程使用;
- 可选配置library、shared
plugins: [
new ModuleFederationPlugin({
// 可自行定义
name: 'base',
// 实测type定义无影响, name需与外层一致
library: { type: "umd", name: "base" },
// 可匹配拆分chunk
filename: "js/remoteEntry.js",
exposes: {// 全部导出的组件
// 名称根据版本加前缀: ./
// 地址为相对路径, 相对此文件
'./RankList': './src/rank-list/index.js'
},
shared: {// 使用容器内与此处保持一致
"react": {
singleton: true,
eager: true,
requiredVersion: '*',
},
"react-dom": {
singleton: true,
eager: true,
requiredVersion: '*',
},
}
}),
]
使用容器配置
- 必须配置remotes用以指定动态远程容器地址;
- 可选配置shared: 公共依赖项,
plugins: [
new ModuleFederationPlugin({
remotes: {
// key可项目内自行定义,
// name为提供容器内name字段
// https://localhost:8090/ 需修改为提供容器的项目构建后部署地址
// js/remoteEntry.js 需修改为提供容器的项目的filename, 即output内publicPath+ModuleFederationPlugin内的filename
key: `name@https://localhost:8090/js/remoteEntry.js`,
},
shared: {// 与提供容器内一致
"react": {
singleton: true,
eager: true,
requiredVersion: '*',
},
"react-dom": {
singleton: true,
eager: true,
requiredVersion: '*',
},
}
}),
]
使用
引入远程组件需使用React.lazy(>=react16.8)方式,
const RankList = React.lazy(() => import('key/RankList'));
const RankListWrap = props => {
return <>
<React.Suspense fallback={<Spin />}>
<RankList {...props} />
</React.Suspense>
</>
}
此时大功告成.
注意事项
除去webpack上已知的错误, 若在webpack内配置了optimization, 其中的splitChunks项目的chunks: "all", 会导致导出的容器不可用, 报错为配置的远程js报错, 注释chunks配置使用默认即可正常运行, 原因可能(瞎掰)为chunks: "all"会破坏本地打包的分包, 导致导出的模块匹配不到.
shared字段内提供容器和使用容器内须保持一致.
容器导出和使用是可以同时存在的, 但是这样会导致去中心化, 不利于后续统一维护迭代, 故本项目采取了中心化配置, 多个项目使用的组件统一导出, 各位大佬可根据项目采取不同方式处理.
有关模块联邦的后续使用遇到的问题、总结的经验会不断更新至此文章.