在上一篇博客深入解析 Webpack Module Federation 的 Shared 依赖版本协商机制,我们已经详细的分析了各种不同shared配置之下,版本协商是如何进行的。
然后有不少同发现仅配 requiredVersion 时的版本选择并不是简单的“谁先加载了就用谁”,今天想通过这篇文章解答一下
仅配 requiredVersion 时的版本选择细节
var loadVersion = (scopeName, scope, key, eager, requiredVersion, fallback) => {
if (!exists(scope, key))
return useFallback(scopeName, key, fallback);
var satisfyingVersion = findSatisfyingVersion(scope, key, requiredVersion, eager);
if (satisfyingVersion)
return get(satisfyingVersion);
warn(getInvalidVersionMessage(...));
return get(findLatestVersion(scope, key, eager));
};
var findSatisfyingVersion = (scope, key, requiredVersion, eager) => {
var versions = eager ? eagerOnly(scope[key]) : scope[key];
var key = Object.keys(versions).reduce((a, b) => {
if (!satisfy(requiredVersion, b)) return a;
return !a || versionLt(a, b) ? b : a;
}, 0);
return key && versions[key];
};
关键认知点:
findSatisfyingVersion会在所有可用的版本中,选出“满足 requiredVersion 且版本号最大的那个”- 若没有任何版本能满足 requiredVersion,
loadVersion还会兜底选最新(findLatestVersion)
这很关键:不是“谁先注册谁先用”,而是总是倾向于用“满足 semver 且最大的那个”。
实验结论验证
基于以下依赖结构:
- host 应用:引用
axios@1.6.8,并shared配置{ axios: { requiredVersion: '1.6.8' } } - remote 子应用:引用
axios@1.10.0,并shared配置{ axios: { requiredVersion: '^1.5.0' } }
实测结果如下:
- host 首先加载时,matching 的只有
1.6.8,就先用它 - remote 需要加载自己的 1.10.0,而 1.10.0 比
^1.5.0匹配范围更大、版本号也高,于是 remote 实际会加载自己的 1.10.0 - 两端都用各自版本,符合 runtime 选择“最大满足条件”的版本的策略
反直觉却合理的机制
这种做法其实有点反直觉。
很多开发者下意识以为:只要第一个满足 requiredVersion 的就直接用那个,但 Webpack MF 选择了在符合 semver 范围下尽可能用最大版本。
原因:
- 满足 semver 的最大版本,理论上具备旧特性的兼容性,也能兼容新特性,利于多远端版本协同时减少重大兼容隐患。
- 若存在 breaking change 危险,建议配合 strictVersion。
最佳实践建议
- 明确主版本统一:MF 项目强烈建议所有 host/remote 尽量依赖同一主版本(如 axios@1.x)。
- 充分测试:如果允许 shared 时存在多版本,需在本地和 CI 全面覆盖兼容性场景。
- 如需严格一致,启用
strictVersion: true,确保 runtime 强制版本一致,否则直接报错,拒绝混用。
总结
Webpack Module Federation 的 shared 依赖协商机制并非简单“谁先用谁的”,而是综合按 semver 匹配尽可能选择最大版本。这一点对于维护复杂微前端架构时确保依赖一致性和新旧兼容,至关重要!
如果你还在为版本选择疑惑,建议直接研读源码并实际搭配配置进行测试,才能真正理解自己的项目在微前端环境下是如何运行的。如果有更复杂的多次 fallback、多个 remote 组合情况,也欢迎交流讨论!
参考阅读: