首发于 语雀@blueju
前言
其实这个问题有点复杂,涉及到好几个场景的混合,关键词:
- 基于 qiankun 的微前端
- 基于 umijs 的基座及子应用(React 技术栈)
- 基于 bpmn.js 的工作流
紧急程度
高
这个问题其实在云效面板上挂了很久了,小小组长们尝试过但没有解决,最近项目组上线急需,我才亲自去处理的,哈哈哈不是我王婆卖瓜自卖自夸啦。
问题
基座加载完子应用后,打开查看工作流流程页面时发生报错,错误信息为无法实例化 BpmnViewer
错误截图我得找一找,过去有一段时间了,不知道还能不能找得到
原因
调试查阅源码后,发现 BpmnViewer 构造函数中有一逻辑,使用 Array.prototype.split 操作 bpmn:xxxx,判断结果长度是否大于2。
基座加载完子应用后,Array.prototype.split 方法失效,无法再支持正则表达式,而该逻辑中正好使用的就是正则表达式。
具体进展
- 将实例化 BpmnViewer 构造函数的逻辑放入基座,未加载子应用前正常运行,说明与基座环境无关。
- 基座加载子应用后,实例化 BpmnViewer 构造函数的逻辑无法运行,初步说明与基座加载子应用有关系,怀疑是 qiankun 中 js 沙箱代理的原因。
- 将怀疑原因报告至 qiankun github issue 及钉钉 qiankun 交流群。
- 使用 react 脚手架 cra 搭建一个纯净无其他干扰代码的子应用环境,在接入基座后,该子应用内的“实例化BpmnViewer 构造函数的逻辑”正常运行,说明初步怀疑 qiankun 中 js 沙箱代理不成立。
- 使用 umi 脚手架搭建一个纯净无其他干扰代码的子应用环境,在接入基座后,该子应用内的“实例化BpmnViewer 构造函数的逻辑”仍无法运行,确认怀疑是 umi 应用的问题。
- 通过反复地卸载可能依赖、打断点、打 log、比较打包结果等一步步操作进入,最终发现是 core-js 中的 core-js/modules/es.regexp.exec 导致的。(可能原因:core-js v3.6.5版本过低,目前最新core-js版本是v3.20.2,umijs 采用的方案是 package.json 内直接锁定依赖,统一由 umi 负责何时升级,以防止第三方 npm 包恶意升级导致 umi 崩溃)
- 通过在基座加载完子应用,动态加载 core-js 二次执行,然后执行“实例化 BpmnViewer 构造函数的逻辑”,正常运行。
- 以上动态加载发生在子应用渲染后,意义不大,我们需要的是基座一加载完子应用,但在子应用渲染前,执行 core-js-bundle,重新覆盖被污染的原型对象方法 Array.prototype.split。(解决措施包括但不限于:升级间接依赖、手动修改node_modules依赖、手动实现 umi 的 targets 功能、子应用入口文件动态 import 最新版 core-js、子应用生命周期 mount 动态 import 最新版 core-js)
- 通过覆盖的方式将最新版的 core-js-bundle 在入口文件执行(core-js 本身也是通过覆盖污染原型的方式实现的向低版本浏览器兼容),将 umi 中较低版本 core-js 进行重置,以回复正常正确的 Array.prototype.split 方法。