解决微前端 qiankun 使用 DllPlugin 抽离公共依赖库使得响应式失效的问题

230 阅读2分钟

前情提要

有一天,项目经理突然让我给一个陌生的项目增加一个新需求,给了我一个 6.0 版本的产品包。在安装项目依赖的过程中出现了一些错误,于是我删除了 pnpm-lock.yaml 文件并重新生成、安装依赖(可能执行了 pnpm update 命令)。

需求部署之后发现,切换菜单时,有一个子包(后续称作管理中心)会默认打开弹窗。弹窗的代码控制是这样的:

<template>
    <el-button class="m-l-sm m-r-sm" @click.stop="openDialog" icon="el-icon-upload2" :disabled="disabled">导入 </el-button>
    <el-dialog title="导入Excel新增数据" :close-on-click-modal="false" :visible.sync="dialogVisible" width="480px" append-to-body>
     xxxxx
     </el-dialog>
</template>

错误排查

我开始了第一步排查,先在 template 中打印 dialogVisible 的值。发现首次进入管理中心时,一切正常。但当切换到其他菜单再回到管理中心时,dialogVisible 的值却变成了:

image.png

看到这个结果后我蒙了,dialogVisible 是通过 Composition API 的 reactive 来定义的,在 template 中应该会自动解构啊。没有头绪之后,我开始梳理这个版本的项目结构。

项目使用 qiankun 的微前端架构,对于公共组件已经使用私有组件库进行抽离。而版本不变的公共依赖,比如 'vue-router'、'vuex'、'@vue/composition-api' 则使用 webpack 的 DllPlugin 进行打包放在服务器上,在各个子项目的 index.html 通过 <script src="/…/dll/dll.vendor.js"> 进行引入。

那么,子项目打包的正常流程就是执行 pnpm run build,webpack 会读取项目配置,在项目配置的 plugins 中包含 DLL 生成的 manifest 文件,所以遇到 'vue-router'、'vuex'、'@vue/composition-api' 等依赖则不会再次打包。在浏览器中访问项目时,则直接使用 dll.vendor.js 中的依赖。

而现在子项目在打包时,会再次打包与 DLL 中版本不符的 @vue/composition-api,导致在切换菜单时 Vue 运行实例会重复安装 @vue/composition-api。

于是在浏览器中打断点查看 composition-api 源码中关于 initSetup 函数,可以看到一个实例中包含两个初始化方法。这也就验证了在 template 中使用 {{}} 查看 dialogVisible 值不是 false 的原因。但是为什么是 {value: false},我继续深究也没追明白。

image.png

总结