vuejs / composition-api

Composition API plugin for Vue 2

Home Page:https://composition-api.vuejs.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

微前端架构下,子应用重复注册 composition-api 插件失败,导致插件提供的响应式 API 不可用

liyongning opened this issue · comments

  • 微前端架构(主应用 A、子应用 B、子应用 C)
  • 主应用通过 CDN 引入 vuejs 库
  • 子应用设置 externals vue,此时这套架构下的应用会共用全局对象(window)上的 Vue。

    注意这里不考虑子应用重命名 Vue 的操作,因为不是一个普适的方法,假如我有 100 个子应用,这个操作就很恐怖了

  • 这时,在浏览器打开子应用 B 中的某个页面,这时一切正常,不会有问题
  • 接下来从子应用 B 进入子应用 C,就会出问题了,提示插件已经被注册过了,且子应用 C 中的响应式 API (比如 reactive)调用也会报错,理由如下:
    • 从第一个子应用进入第二个子应用(从 B 进入 C),当在子应用中引用 composition-api 时(import CompositionAPI from '@vue/composition-api),会触发插件中的如下代码:
    if (typeof window !== 'undefined' && window.Vue) {
      window.Vue.use(Plugin)
    }
    • 进而会注册插件,执行插件的 install 方法,从而触发 install 中的检测方法 isVueRegistered,代码如下:
      export function install(Vue: VueConstructor) {
        if (isVueRegistered(Vue)) {
          if (__DEV__) {
            warn(
              '[vue-composition-api] already installed. Vue.use(VueCompositionAPI) should be called only once.'
            )
          }
          return
        }
        // ....
      }
    • 接下来触发 isVueRegistered 方法
      export function isVueRegistered(Vue: VueConstructor) {
        return hasOwn(Vue, PluginInstalledFlag)
      }
    • 因为子应用共用全局对象上的 Vue,所以 isVueRegistered 方法会返回 true
    • 导致 install 方法无法继续往下执行,也就是说子应用 C 中的 vueConstructor 变量是 null
    • image
    • 这时插件虽然在路由进入子应用 B 时已经在 Vue 上注册了,但是当切换到子应用 C 时由于 install 被提前终止,导致下面的 setVueConstructor 没有执行,所以 vueConstructor 变量是 null,代码如下:
      • image
      • image
    • 这时子应用执行响应式 API 时,比如 reactive,执行过程如下:
      • image
      • image
      • image
    • 所以这时候控制台就报错,找不到 Vue

=============================================================================================

针对以上问题,有如下解决办法,可以增强 isVueRegistered 方法的判断能力,比如:
image
目前通过给插件 打补丁 的方式在业务中运行该方案,经验证是可行的,也没发现什么副作用,composition-api 的单元测试也能正常跑过