前言
随着 umi@4 和 bigfish@4 的建设,mfsu 也迎来了一波强力更新,可以看云谦老师写的文章《Bigfish 4 特性 01:MFSU V3》。本文从更详细的技术角度,分析 MFSU V2 和 V3 的区别,帮助彻底了解 V3 带来的提升以及相关的技术原理。
我对于 Umi 来说还是太年轻了 ——牧亿
引用一下提到的文章中关于 mfsu 的主要优化的描述:
- 不再需要手动 rm -rf src/.umi
- 不再有奇怪的问题
- 大项目在浏览器打开也快了
要想了解这个问题,首先对比一个 mfsu V2 和 V3 的实现区别。
重看 mfsu V2
详细的可以看之前的这篇文章:https://yuque.antfin.com/docs/share/7751efb7-8a3d-4141-bc70-a8db696437ba?# 《MFSU 是什么?从痛点到技术选型》
mfsu 的主要实现流程可以用以下流程表示:
问题一:总是需要手动删除 src/.umi
理解:因为 mfsu 的 remote app 存储在 src/.umi/.cache/.mfsu 中,并且 mfsu 根据 babel 插件搜集的代码进行是否重新编译决策。如果依赖未及时搜集,会导致 webpack 使用 module federation 加载远程模块时报错。
问题二:总有奇怪的问题
理解:因为 mfsu 的 babel 插件对源码进行编译的时候,将所有引用变成 await import 的形式,带来了很多限制。例如源码中不允许使用 require 引用代码,并且需要使用全局 await import,兼容性很差。(包括 umi 的 plugins,当初做了很多工作来使插件兼容 await import 的形式)
问题三:大项目在浏览器打开很慢
理解:因为 mfsu 打包时做了 chunks 分割,每一个包单独打包。在大项目中打开时,需要同时拉取近百个依赖包,超过 http 协议并发承载能力。
那么 MFSU V3 是怎么解决这个问题的呢?这就不得补佩服云谦老师的牛逼了。
MFSU V3
前置功课:webpck-virtual-modules
这是一个 webpack 插件,用于生成一个虚拟模块,用一个简单的例子快速理解一下;
const VirtualModulesPlugin = require('webpack-virtual-modules');
module.exports = {
plugins: [
new VirtualModulesPlugin({
// 在此构建了一个虚拟模块 [module_name] : [module_file_content] 的形式
'node_modules/virtual-module.js': 'module.exports = {foo : "foo"}',
}),
],
}
import vModule from 'virtual-module';
console.log(vModule);
// {foo : "foo"};
一句话总结:可以无需编写文件,即可在 webpack 中插入一个模块。
为了让大家边看边理解,在这先把 mfsu@3 的方案三句话总结一下:
- 通过 virtual-module 构建虚拟入口,并使用 await import 加载真实入口和依赖。
- 随后依赖会被缓存到 webpack 的 module_cache中。
源码直接引用 module_cache 中的包,而无需进行 await import。
V3 的实现流程
同样,no picture say a bird:
对比上图,可以看到显著的变化:实际运行的代码没有了 await import,这是解决大部分“奇怪问题”的关键。
- await import 仍然存在,不过只使用一次,且和用户代码无关联。
- 左下角的 remote app 现在只会生成一个大的依赖文件,这就很快。
生成依赖图和主流程关系不大,因此感兴趣的同学可以直接去看源码
// V2
const {
default: React
} = await __webpack_require__.e(/*! import() */ "webpack_container_remote_mf_react").then(__webpack_require__.t.bind(__webpack_require__, /*! mf/react */ "webpack/container/remote/mf/react", 23));
// V3
/* harmony import */ var mf_Users_muyi_github_umi_next_node_modules_pnpm_react_17_0_2_node_modules_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! mf//Users/muyi/github/umi-next/node_modules/.pnpm/react@17.0.2/node_modules/react */ "webpack/container/remote/mf//Users/muyi/github/umi-next/node_modules/.pnpm/react@17.0.2/node_modules/react");
总结
相关链接
对更多细节感兴趣的同学可以查看一下: