Umi MFSU 的 normal 与 eager 两种策略怎么选
2026/9/15 17:08:22 网站建设 项目流程

Umi MFSU 的 normal 与 eager 两种策略怎么选

【免费下载链接】umiA framework in react community ✨项目地址: https://gitcode.com/GitHub_Trending/um/umi

MFSU 是 Umi 默认开启的、基于 webpack5 Module Federation 的打包提速方案:它把应用源代码的编译和应用依赖的编译分离开,把变动较小的依赖构建成一个 Module Federation 的 remote 应用,这样热更新时不需要重新编译依赖,热更新时间会明显缩短。MFSU 的关键在于如何把应用代码实际用到的依赖分析出来,而normaleager就是两种不同的分析方式,直接决定了构建是串行还是并行、冷启动快还是慢。这篇文章基于 MFSU 指南和配置项文档,说明两种策略的工作方式、适用场景,以及选定策略后如何对照文档判断已知问题。

策略配置在哪里改

MFSU 默认开启,strategy的默认值是'normal'(完整默认值为{ mfName: 'mf', strategy: 'normal' })。要切换策略,在 Umi 配置里修改mfsu.strategy

// 使用 normal 策略(编译时分析) mfsu: { strategy: 'normal', }
// 使用 eager 策略(扫描方式) mfsu: { strategy: 'eager', }

不打算使用 MFSU 时,配置mfsu: false关闭即可。参数细节可对照 mfsu 配置项,完整的策略说明见 MFSU 指南。

normal:编译时分析,构建过程串行

normal 策略的工作方式是:先对应用项目源码单独进行编译,编译的同时收集项目本身的依赖,以及转译过程中由转译器(比如 babel)插入的新依赖。这些插入的依赖在项目代码层面不可见,只有通过转译的插件才能收集到。项目代码编译完成后,MFSU 再拿收集到的结果去构建依赖部分的代码。

整个流程是串行的:先编译项目代码,再构建依赖。

它的好处是收集到的依赖是完整的,项目代码和依赖代码的构建打包完全分离;项目代码修改以后只需要构建项目代码部分。缺点就是构建过程串行,耗时会叠加。

eager:静态扫描,编译并行

eager 策略不做编译时分析:它先读取项目中的所有源代码文件,通过静态分析获取项目依赖,然后拿着这份依赖信息,并行进行项目代码的编译和依赖的编译。

文档给出的示例数据(文档示例,非所有项目的固定预期):在一个 17 万行代码、1400 多个文件的项目中,静态分析一次只需要 700ms 左右。并行的代价是:静态分析收集到的依赖会缺失后面项目代码编译时插入的依赖,这部分依赖最终会和项目代码一起编译打包。

针对这个缺陷,配置项提供了include参数,它仅在strategy: 'eager'模式下生效,用于补偿静态分析无法分析到的依赖:

// 例如 react 未进入 Module Federation 远端模块时 mfsu: { strategy: 'eager', include: ['react'], }

按文档的选择依据决定策略

MFSU 指南给出了明确的选择建议,对应如下项目形态:

项目情况文档建议
不使用 Module Federation 功能,项目依赖变动不频繁先尝试 esbuild 构建
monorepo 项目使用normal策略,推荐同时开启monorepoRedirect配置
项目较大,项目代码基数较大使用eager策略
项目刚刚启动,会频繁改动依赖使用eager策略
其他类型的项目随意选择

其中两点值得展开:

  • esbuild 构建:MFSU 支持用 Webpack 或 esbuild 构建项目依赖,默认是 Webpack。通过mfsu: { esbuild: true }开启后依赖的预编译走 esbuild,首次启动更快;缺点是二次编译不会有物理缓存,稍慢一些,所以文档推荐依赖比较稳定的项目使用。
  • monorepo 场景monorepoRedirect会把其他子包的导入重定向到它们的源码位置,除了支持热更新、无需预构建子包,文档也明确说它"可以解决MFSU场景改动子包不热更新的问题"。这正是 monorepo 选normal时搭配它的原因,参数用法见 monorepoRedirect 配置项。

应用策略后,如何判断状态和已知问题

文档没有给出统一的计时命令来对比两种策略的耗时,但可以依据文档描述的行为特征和已知错误现象来判断当前策略是否工作正常。

判断 eager 的扫描是否生效:文档示例中 eager 的静态分析耗时在千行万行规模的项目里是几百毫秒级(上文 700ms 为该文档对应项目的示例值),如果扫描明显慢于这个量级,说明项目规模或依赖状况不同,需要结合下面的错误现象排查。

依赖缺失(eager 常见):出现如下报错时,检查对应依赖是否已经安装:

error - [MFSU][eager] build worker failed AssertionError [ERR_ASSERTION]: filePath not found of lodash.capitalize

React 多实例问题:某些复杂场景下 React 的代码被打包多份,运行时产出多个 React 实例并在浏览器报错。解法是通过 Module Federation 的shared配置避免多实例:

mfsu: { shared: { react: { singleton: true, }, }, }

注意:如果开启了 MF 插件,需要开启shared,参考 MF 插件文档。

依赖环问题:monorepo 中项目依赖 A 包、A 又依赖 monorepo 子包 B 时会形成依赖环,或者某个依赖的实现引用了.umi目录下的内容导致开启 MFSU 后不能正常编译。这两种情况都通过mfsu.exclude配置解决:

mfsu: { exclude: ['B'], }

exclude支持字符串(全词匹配)或正则。另外如果项目代码需要在 Worker 中使用,必须把 Worker 需要的依赖加进exclude——因为 Module Federation 通过window对象共享模块,Worker 中无法使用这些模块。

externals script 兼容问题:如果项目依赖 a、a 依赖 b,而 b 配置了 script 类型的 externals,开启 MFSU 时import * as b from 'b'拿到的会是Promise<Module>而不是正常的 Module 信息(文档判断为 webpack 对 externals script 和 Module Federation 兼容处理的问题)。解法是不让两者混用,只在生产环境开启该 externals:

externals: { ...(process.env.NODE_ENV === 'production' ? { b: ['script https://cdn/b.js', b] } : {}), }

小结

选择路径回到项目形态本身:依赖稳定的项目按文档建议先试 esbuild 构建;monorepo 用normal搭配monorepoRedirect;代码基数大的项目和依赖频繁变动的新项目用eager,配合include补偿静态分析不到的依赖。选定后,文档列出的依赖缺失报错、React 多实例、依赖环和 Worker 限制就是判断策略是否顺畅、以及该用sharedexcludeinclude中哪一项去修的直接依据。MFSU 缓存默认放在node_modules/.cache/mfsu,也可以通过cacheDirectory配置项调整位置,便于在排查时定位缓存产物。

【免费下载链接】umiA framework in react community ✨项目地址: https://gitcode.com/GitHub_Trending/um/umi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询