🙋🏻♀️ 编编拎重点:本文是蚂蚁集团前端工程师云谦关于 Umi 4 新特性系列分享的第一篇,后续将陆续更新 Umi 4 的其他新特性,欢迎查阅。
Umi 3 的 MFSU 大家多少都有接触过,虽然有用,但 DX 不够好。用的时候会遇到一些坑,以至于很多同学都掌握了一项特殊技能,遇到问题时 rm -rf src/.umi。除此之外,大家遇到的问题还有,
1、如果用 monorepo 组织项目,mfsu 是不支持的
2、特殊场景的热更新问题,可能会导致 Tab 卡死
3、虽然二次打开快(因为有缓存),但首次还是慢
4、启动虽然快了,但大项目的页面打开反而慢了,因为请求多
5、样式的优先级问题,比如 antdpro 或自定义的样式如果比 antd 早加载就会失效
6、不支持 export * from 语法,只能用具名的 reexport,比如 export { foo } from
7、不支持 require 语法,只能用 import 或 import()
8、没有 export 信息的文件会自动加上 export const __mfsu = 1
9、...
以上问题,在 Umi 4 的 MFSU V3 中全解了!再也没有各种奇奇怪怪的问题,也不用手动 rm -rf src/.umi 了!基于此,我们非常有信心地在 Umi 4 中默认开启 MFSU 功能。当然,如果你不喜欢,会保留手动配置 mfsu: false 关闭的口子。
为啥不再需要手动 rm -rf src/.umi ?因为 MFSU V3 内置了 Module Graph,会收集所有项目文件的依赖关系,做到精确更新,不会在需要预编译依赖时不编译,同时也只在必要时做依赖的重新预编译。
为啥不再有奇奇怪怪的问题?因为内部调整了 MFSU 的实现,用更 webpack 的方式使用 webpack。上个版本(MFSU V2)会把 import 'foo' 替换为 await import('mf/foo'),让整体链路异步化,然后由于社区很少有人这么用 webpack,引入了不少 hack 解各种边界条件,所以会导致一些奇怪的问题。这个版本(MFSU V3)把 hack 逻辑全删,一个不剩,只对 entry 文件做异步化,因为我们发现,只要 entry 异步了,webpack 会自行处理后续依赖链路的异步化。
图:SEE Conf 2022 上分享的 MFSU 原理图
为什么大项目在浏览器里打开也变快了?启动快但浏览器打开慢是 Bundless 方案(包括 Vite)的通病,原因是请求多。MFSU 的解法是和 Bundle 方案一样通过 code splitting 做 chunks 合并,把大部分依赖合到一个文件里,从此不再有请求数量问题。
monorepo 是如何支持的?monorepo 在 Umi 4 中有重点考虑,已有其他公司的包含 60+ 项目的大型 monorepo 踩过 MFSU 的坑了。monorepo 的支持分两部分,1)要能找到 monorepo 中的其他 package,2)package 不能当成依赖,package 的修改要能立即生效。前者内置支持,后者通过 monorepoRedirect: {} 配置支持。
MFSU 到底有多快?Umi 4 中其实有内置 Vite 模式,之前我们用两个示例、四种模式、四个维度做了对比对比。两个示例分别是大型的全量 ant-design-pro 和小型的 libs example;四种模式分别是 webpack、webpack + MFSU、webpack + MFSU with esbuild mode、Vite in umi;四个维度分别是无缓存的冷启动、有缓存的热启动、修改代码后的热更新、页面打开速度。详见《比 Vite 还快的 MFSU》。
图:全量 ant-design-pro 速度对比图
图:libs example 速度对比图
One More Thing。MFSU 还有个特性是支持脱离 Umi 独立使用,比如之前是用 CRA 搭的项目,也可以方便的迁移过来,参考文档《独立使用 MFSU》(链接:https://next.umijs.org/blog/mfsu-independent-usage)。