Published on

记一次 qiankun 引发的 bug

Authors

Question

我们的业务与财税相关, 其中有一个功能点是对 ofd 版式文件的预览, 经常开发票的人对这个可能熟悉点. 对我来说这是个新的知识点, 毫无疑问, 咱先去万能的 github 上寻找是否有开源的库可以采用. 经过一番寻找和比对后, 选择了 ofd-tools 这个开源库进行开发.

一切都很顺利, ofd 文件也能顺利渲染, 但前提是在 qiankun 子应用单独启动的时候, 一旦通过主应用打开这个页面预览 ofd 文件时, 就莫名的空白了, 啥也没有, 连控制台的报错信息都没得, 郁闷...

定位

还能怎么办? debug 呗...

我把 github 的仓库克隆到本地, 然后通过 npm link 的方式去调试, 经过半个小时多的努力, 总算让我找到了罪魁祸首!

一路跟踪到了 ofd-tools 的一个叫 jszip 的依赖, 其中有个方法是这么写的:

var onGlobalMessage = function(event) {
    if (event.source === global && // 👈
        typeof event.data === "string" &&
        event.data.indexOf(messagePrefix) === 0) {
        runIfPresent(+event.data.slice(messagePrefix.length));
    }
};

有一点经验的朋友应该一眼就能扫到问题所在了吧, 就是 event.source === global 这里, 如果在乾坤下, global 始终都不会等于 event.source. 以为 qiankun 下的 global 是被 proxy 包了一层代理的, 这也是 qiankun 的沙箱特性1. 找到问题所在, 那剩下的就好办啦.

解决

通常修改这种源码的 bug 有很多方式, 比如直接给原仓库提 pr, 或者直接修改本地的 node_modules 里的代码等.

多方均衡之下, 使用打补丁的方式去处理更加符合现在的项目情况. 由于我们使用的是 pnpm, 直接使用 pnpm patchpnpm patch-commit 命令即可实现. (如果你使用的是 npm, 可以参考 patch-package).

  1. pnpm patch [email protected], 复制一个临时目录, 可以使用 --edit-dir <dir name> 指定
  2. 去临时目录中修改文件
var onGlobalMessage = function(event) {
    if ((event.source === global || global.__POWERED_BY_QIANKUN__) &&
        typeof event.data === "string" &&
        event.data.indexOf(messagePrefix) === 0) {
        runIfPresent(+event.data.slice(messagePrefix.length));
    }
};
  1. 最后, 执行第一步返回的命令: pnpm patch-commit '/private/var/folders/0w/3bs237hx0_5bb5pk_tfqq5140000gn/T/1803a7b5a7b556da907c1199e582b295' 即可,

此时, 在项目目录下就会新增一个 patches 文件夹, 里面有 [email protected] 文件, package.json 中也会增加以下内容:

"pnpm": {
    "patchedDependencies": {
        "[email protected]": "patches/[email protected]"
    }
}

这样, 在后续的安装中, 都会自动安装这个补丁了, bug 也就随之完美解决🎉.

总结

纸上得来终觉浅, 绝知此事要躬行. 说一百遍沙箱, 都不如实实在在的改一次 bug 😂.

额外分享两个打补丁的经验:

  • 对于 Vite, 打完补丁后重启去要添加 --force 命令, 因为 Vite 预构建, node_modules 下的.vite 文件会把加载的依赖做一个缓存.
  • 撤销补丁仅仅删除 patches 文件夹是没有用的, 需要 npx patch-package <pkgName@x> 再重启.

Footnotes

  1. qiankun 2.x 运行时沙箱源码分析