core-js常见于qiankun中的多份polyfill冲突问题

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

问题

开门见山你可能会在 qiankun 等微前端体系中有多个子应用时发生这样的加载崩溃问题:

Cannot redefine property: DEG_PER_RAD

Cannot redefine property: RAD_PER_DEG

实际上 DEG_PER_RADRAD_PER_DEG 都是 Math 上的静态常量在以下的描述中我们就以 Math.DEG_PER_RAD 为例进行拆解。

原因拆解

崩溃的根本原因是core-js3.23.0 做出了一个改动:不能对 Math.DEG_PER_RAD 重复赋值 相关 issue 详见 #1091

在 core-js 3.23.0Math.DEG_PER_RAD 设定为了 nonConfigurable: truenonWritable: true 的 代码详见 esnext.math.deg-per-rad.js 所以当加载了 >= 3.23.0 的 polyfill 后不能对 Math.DEG_PER_RAD 重新写入了此时再加载 < 3.23.0 的 polyfill 就会发生崩溃报错。

而先加载了 < 3.23.0 的 polyfill 再加载 >= 3.23.0 的话是没问题的。

为什么常会发生在微前端下?

通过问题拆解我们发现此报错是与 core-js 不同版本的加载 顺序 强相关的而在 qiankun 类似的微前端体系下往往每个子应用都会有一份 polyfill 所以他们可能会发生本文中的致命冲突导致应用彻底崩溃。

你可以在全局变量 window['__core-js_shared__'] 中看到当前项目中有多少 core-js 版本:

解法

这里我们先不进一步探究直接提供解法:

要解的无非是 Math.DEG_PER_RADMath.RAD_PER_DEG 的问题那我们直接排除这两个 polyfill 就可以了他们在 core-js 中的名字是 esnext.math.deg-per-radesnext.math.rad-per-deg

如何排除?

对于社区中大部分的脚手架来说他们的 babel polyfill 策略都是 usage 所以当你不使用这两个 Math.xxx 常量的时候他是不会引入 polyfill 的。

既然发生了此问题说明你的 polyfill 大概率是 entry 策略此处不再展开讲解 babel polyfill 策略是全量引入的所以你应该找到相关源头排除掉他们。

由于排除的手段和 框架 / 脚手架 实现逻辑强相关所以本文不做具体描述在排除过程中除了可以定点排除 esnext.math.deg-per-radesnext.math.rad-per-deg 外考虑到未来如果新增其他的 Math.constant 常量也要再排除同时 esnext.math.xxx 都是 stage 1 的 polyfill 详见 proposal-math-extensions 几乎不会有人使用到全部排除了也是没什么风险的故可以把 esnext.math.xxx 全部过滤掉。

当你无法触及、或不了解框架行为不能自行解决时可以考虑到相关框架、脚手架的 issue 区反馈寻求维护者的帮助。

swc 的 polyfill 策略排除法

为了讲解的更全面此处我们还提供 swc 的 polyfill 排除解法。对于 swc 来说我们推荐使用的 polyfill 策略是人工指定 includes 方法因为 swc 的 usage 策略速度慢且更新不及时详见:

那在获取 polyfill 列表结束后人工过滤掉 esnext.math.xxx 的 polyfill 即可:

// 过滤部分逻辑
const filteredList = (list as string[]).filter(line => {
  // https://github.com/zloirock/core-js/issues/1091
  // Prevent `Math.DEG_PER_RAD` / `Math.RAD_PER_DEG` constant override problem in qiankun micro app
  return !line.startsWith('esnext.math.')
})

其他可能的解法

除了从 core-js 本身上来解决该问题这里再提供一些其他的解法思路:

  1. 将主应用、子应用全部升级到最新的 core-js 版本避开含有 < 3.23.0core-js 情况可解此问题。

  2. 因为主应用含有 polyfill 子应用没有独立使用的场景时无需 polyfill 把子应用的 polyfill 关掉就可以了。

总结

core-js 本身是没问题的只不过你加载了多份 polyfill 那就说不准了这就是:微前端路漫漫其修远兮只有踩过了坑才知道事出不易。

由于本文探讨的问题场景比较特定和深入更多的面向对 webpack 比较了解的用户跳过了很多基础概念的介绍希望对你有所帮助。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6