前言
前一篇文章尝试将模块联邦进行落地,时隔月余,终于得空来书接上回;期间尝试多种方式进行最大化发挥其能力,最终整理出其最适合场景,分享给大家。
背景
还是这个项目结构,主要改动依然在base project
一、ModuleFederationPlugin配置
先看代码
plugins: [
new ModuleFederationPlugin({
// 可自行定义
name: 'base',
// 实测type定义无影响, name需与外层一致
library: { type: "umd", name: "base" },
// 可匹配拆分chunk
filename: "js/remoteEntry.js",
exposes: {// 全部导出的组件
// 名称根据版本加前缀: ./
// npm
"./axios": { import: "axios", name: 'axios' },
"./classnames": { import: "classnames", name: 'classnames' },
"./core-js": { import: "core-js", name: 'core-js' },
"./immer": { import: "immer", name: "immer" },
"./react": "react",
"./react-dom": "react-dom",
"./react-redux": "react-redux",
"./redux": { import: "redux", name: "redux" },
"./redux-actions": { import: "redux-actions", name: "redux-actions" },
"./redux-logger": "redux-logger",
"./redux-thunk": "redux-thunk",
"./antd": { import: "antd", name: "antd" },
"./@ant-design/icons": "@ant-design/icons",
// 地址为相对路径, 相对此文件
"./libs": { import: "./src/libs/index", name: 'libs' },
// comps
'./RankList': { import: './src/rank-list/index.js', name: 'RankList' },
'./ModalInfoMedals': './src/modal-info-medals/index.js',
},
shared: {// 使用容器内与此处保持一致
...npmLibsObj,
"react": {
singleton: true,
eager: true,
requiredVersion: '*',
},
"react-dom": {
requiredVersion: '*',
},
}
}),
]
其中变化的部分为
exposes、shared
-
exposes内的value部分可配置为对象,配置name后,可在其它项目使用时作为文件名称 -
shared内可将package.json内的dependencies全部npm依赖共享出去其中
shared内的key对应的value对象若只配置requiredVersion,打包后的js/remoteEntry.js内只会增加对应key的引用(不拷贝key对应的文件本身),若同时配置了singleton或eager,则会拷贝key对应的文件本身;实测本react项目仅配置react用以实现单例即可。 -
引入
dependencies并稍加处理const npmLibs = require("../package.json").dependencies const npmLibsObj = {}; Object.entries(npmLibs).map(([key, version]) => { npmLibsObj[key] = { // singleton: true, // eager: true, requiredVersion: version, } }) -
analyzer结果如下
除去
react,其余均为对象引用,此时的js/remoteEntry.js文件最小最干净
二、打包关键配置
依然要保持chunks不为'all',同时为实现基础模块就近使用,这里改为了chunks: (chunk) => false,,而cacheGroups内只配置default: false,就可。
optimization: {
splitChunks: {
// chunks: 'all',
chunks: (chunk) => false,
automaticNameDelimiter: '-',
cacheGroups: {
default: false,
}
},
},
三、其余remote项目
无需任何调整🥳🥳🥳
虽然我很想这么说
最好也将全部package.json内的dependencies全部依赖共享出去
目前发现
"react-router-cache-route", "react-router-dom", "react-redux"这三个包不可以在remote项目内同时shared,会导致白屏,暂时未排查出具体原因
四、效果
前三个js分别为模块联邦入口、core.js、远程组件
本地
生产
第四个为增加
name的远程组件
总结
针对模块联邦的定位官方文档说的也很清楚,简单来说,就是按需加载的远程组件/库;
主要通过提取公共的组件/库,以供其他remote项目使用,实现了组件的中心化维护、迭代;按需加载的特性可以进一步降低打包产物大小、节约客户端网络带宽、提升SPA应用加载/渲染性能;shared特性可以进一步缩短组件依赖加载路径,更彻底的剥离业务代码。
个人认为,最佳场景是基于相同基础包所构建围绕相同业务的平行多项目集群,换句话说就是适合上微前端的项目集群都十分适合模块联邦;
菜鸡献丑,大佬们轻喷