一、背景
在写组件库的时候,引入了一个组件,vscode瞬间飘红,仔细看引入方式并没有什么问题
保存后在控制台查看后报错如下
报错指向了这个文件(但这个不是我们刚保存的文件)
二、分析原因
首先看报错信息,
Uncaught ReferenceError: Cannot access 'ExtraInfoList' before initialization
(偷懒惯例先问下chatGPT)
新开发遇到这种问题肯定有点懵,老开发一看到before initialization和报错就大概可以猜出来了,可能是组件循环引用了,导致其中没有初始化的时候就被调用出错。
那此时我回去分析了一下具体的引用逻辑,大概像这样。还是三个组件的循环调用哈哈,不过这也比较符合一开始组件库设计的初衷,感兴趣的可以看下之前讲组件库设计的那篇。https://www.jianshu.com/p/1c46600b3e44
模块系统发现它需要 A,但是首先 A 依赖 B,但是 B 又依赖 C,但是 C 又依赖 A,如此往复。这变成了一个循环,不知道如何不经过其中一个组件而完全解析出另一个组件。为了解决这个问题,我们需要告诉模块系统一个点:“A 是需要 B 的,但是我们不需要先解析 B,只在需要的时候引入即可。”
三、解决方案
进行异步引入即可,需要注意的是,vue3需要使用一个defineAsyncComponent去定义一个异步组件。代码如下:
Vue2
components: {
BottomTags: () => import('../../bottom-tags/bottom-tags.vue')
}
Vue3
import { defineAsyncComponent } from 'vue';
components: {
BottomTags: defineAsyncComponent(() => import('../../bottom-tags/bottom-tags.vue') as any)
}
但是由于我的组件库是Vue-demi
一套代码兼容vue2和vue3,所以需要对两种情况进行兼容
import { isVue2, defineAsyncComponent } from 'vue-demi';
components: {
// https://cn.vuejs.org/guide/components/async.html#basic-usage
BottomTags: isVue2 ? () => import('../../bottom-tags/bottom-tags.vue') : defineAsyncComponent(() => import('../../bottom-tags/bottom-tags.vue') as any),
}
参考:
https://cn.vuejs.org/guide/components/async.html#basic-usage
https://stackoverflow.com/questions/69645120/invalid-vnode-type-undefined-undefined-when-used-with-component-is-comp
https://stackoverflow.com/questions/72977357/vue-3-dynamcially-load-async-components