技术栈背景:
{ ..., "ant-design-vue": "~3.2.15", "vue": "^3.2.45",... }
事情是这样的: 前两天春节假期结束刚上班,运营反馈线上使用的CMS平台弹窗没办法关闭,找到组内的前端小伙伴问什么情况。 我正好也在旁边就过去一起看看,结果发现一个因为版本号引起的问题。 因为公司的CI/CD机器我们没办法登录进去,只能通过CI机器的日志来查看问题,但是发现没啥用,没啥有用的日志输出。也猜测过是安装包的版本问题,前期也检查过,本地一切正常,测试环境一切也正常,但是线上环境就异常
前端小伙伴首先在本地打开页面,经过反复测试弹窗功能正常,后面发到测试环境发现还是一切正常,又改了弹窗文件js,重新发了生产环境 确认了打包的静态资源的contentHash也变了,但是功能还是不正常(更改文件是为了确保hash变更,不是缓存造成的干扰)。
线上环境代码是经过压缩混淆的,下面的代码截图只是方便大家解读和理解
结论: vue3.4.x 源码变更了组件update方法。
-
v3.4.0-alpha.1 版本以上 和v3.4.0-alpha.1 以下的版本在这里的差异主要是组件的渲染,增加了 effect.dirty 这个判断
-
这个 effect 在vue3里面相当于vue2的 Watcher实例,我们先来复习下 vue2有三种 Watcher实例(render watcher 我们俗称的渲染watcher,computed watcher, watcher api的 watcher) Vue2 每个组件都是一个 Watcher实例,所以每个组件都有update方法。computed 对象的每个 value 也是一个Watcher实例。我们直接使用的 watch 对象的每个 value 也是一个Watcher实例。
-
vue3 没有使用 Watcher, 使用了Effect,本质上和 vue2 的Watcher一样,都是充当观察者角色。收集页面上使用被变更的数据
-
3.4.x 版本以下 @vue/runtime-core的 render.ts 更新组件的写法
- 3.4.x 版本以上 @vue/runtime-core的 render.ts 更新组件的写法
下面是探究的过程,觉得啰嗦可跳过:
- 在弹窗产生的地方打断点,发现弹窗对象上有两个方法update和destroy,分别对应的是ant-design-vue更新弹窗和销毁弹窗方法
- 在断点处,手动调用 window.testaa.destroy(window.testaa 是我手动在 window上面挂的弹窗实例) (), 弹窗依然没有关闭。通过定位到ant-design-vue的源码,发现在组件更新这里出现了问题(confirmDialogInstance.component.update())
至此, 断点过程已经结束,我们也顺利找到了问题,vue3.4.x 源码变更了组件update方法。刚开始,我们的同学以为是代码问题,花了点时间去查找,遇到问题还是要静下心来仔细查找
疑问点:
- 3.4.0版本距今发布已经2个月了,为什么现在才出现这个问题? 我仔细查过也想过这个问题
- 我们一直使用的是pnpm来安装包,pnpm有缓存node_modules安装包的能力, 我们业务写的vue版本是^3.2.45,这里的^ 代表大版本不升级即可,所以3.4.x 是符合我们这里^符号的规则,也合理的解释了为什么出现了 3.4.x版本的依赖。
- 为什么测试环境 本地环境都是正常的,线上不正常?
- pnpm在安装过程中优先查找缓存的npm包,本地因为缓存过3.2.x版本的包,所以删除node_modules 再次安装此时拉取的还是缓存里面的包,所以功能也还是正常展示的。
- 线上不正常的原因我想了很久没有想通,我一开始猜测,有一个A项目依赖了 vue 3.4.x 这个版本,他在CI机器第一次构建的时间点比我们第一次构建的时间点要早(我们这个是最近迁移到这个CI机器的,之前这个CI机器有其他项目在跑),我们项目正好用了^3.2.45, 此时 A项目的 vue 3.4.x也符合我们的安装语义,但是在随后的测试中这个观点不成立,希望知道原因的读者在评论区留下答案
规避点:
- 拿到一个新项目先看下依赖,心中做到一个大概的预知,发现问题,往几个可能存在的方向去验证,大胆猜测,小心验证
- 版本控制要做好(建议不要直接写死版本,这样没办法拥抱别人更新的新特性)
- github上关于这个问题的两个 issues
- github.com/vueComponen…
- github.com/vuejs/core/…
意外的零花钱:
- 访问这个url: provisions.starknet.io/
- 点击这里,输入自己的github名字即可看到有多少个币(一个接近2美元,汇率目前7.2 --> 2 * 7.2 * 你的币)
- 比如: yyx990803(vue作者) 中了价值 1500¥ (不要的话欢迎打给我,我的钱包地址: 0x124109a84D8378b75ddc30Cf6f5e177dCB3B1c86)