问题
保存时仍需报错 但是F5正常 打包也正常

ini
chunk-ZHNFVA5M.js?v=ac948eb1:11432 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'nextSibling')
at nextSibling (chunk-ZHNFVA5M.js?v=ac948eb1:11432:35)
at removeFragment (chunk-ZHNFVA5M.js?v=ac948eb1:6679:14)
at remove2 (chunk-ZHNFVA5M.js?v=ac948eb1:6650:9)
at unmount (chunk-ZHNFVA5M.js?v=ac948eb1:6628:9)
at Object.remove (chunk-ZHNFVA5M.js?v=ac948eb1:9303:13)
at unmount (chunk-ZHNFVA5M.js?v=ac948eb1:6603:20)
at unmountComponent (chunk-ZHNFVA5M.js?v=ac948eb1:6713:7)
at unmount (chunk-ZHNFVA5M.js?v=ac948eb1:6593:7)
at unmountComponent (chunk-ZHNFVA5M.js?v=ac948eb1:6713:7)
at unmount (chunk-ZHNFVA5M.js?v=ac948eb1:6593:7)
环境准备
官方原版前端环境(5.5.9版本) 未调整任何配置 具体为
- transition开
- keepAlive关
(后话) 跟上面的都没关系
在什么情况才会出现
之前在项目中测试 只要是xxx.ts(tsx)保存 就会出现该问题 xxx.vue则不会出现
测试非useVbenXXX的页面
先使用playground/src/views/demos/access/index.vue来测试

新建data.ts 然后vue文件引用
data.ts
js
console.log('code code');
index.vue
arduino
import './data';
修改data.ts里的代码(或者直接保存也会触发热更新) 页面正常热更新 没有出现问题
测试useVbenModal/Drawer
文件位置playground/src/views/examples/modal/index.vue

还是同样 引用data.ts
流程跟上面一样 也能正常热更新
测试useVxe
文件位置playground/src/views/examples/vxe-table/basic.vue
data.ts
js
console.log('code code');
export const column = [
{ title: '序号', type: 'seq', width: 50 },
{ field: 'name', title: 'Name' },
{ field: 'age', sortable: true, title: 'Age' },
{ field: 'nickname', title: 'Nickname' },
{ field: 'role', title: 'Role' },
{ field: 'address', showOverflow: true, title: 'Address' },
];
vue
js
onMounted(() => {
console.log('mounted');
});
onBeforeUnmount(() => {
console.log('unmount');
});
然后保存data.ts 也能正常更新 看看Log

卸载再挂载 看起来流程没有问题
换个符合业务带查询的表格试试呢 playground/src/views/examples/vxe-table/form.vue
保存也是正常的 (后话: 因为没有Modal/Drawer) 也没有公用data.ts
混合
使用这个页面测试

保存data.ts后 一定会复现

先把drawer相关的代码移除 发现保存正常了(热更新)

那么确定是useForm的问题?
然后试了 单独 drawer+form 的情况(不包含表格) 没问题?
这就奇了怪了 三个单独使用都没问题 混在一次就有问题了?
然后回到role菜单来测试 保留drawer 但是去除useForm 这样热更新也没问题
只保留一个空drawer 难道是useForm的问题 控制变量进一步探究
js
<script lang="ts" setup>
import type { SystemRoleApi } from '#/api/system/role';
import { computed, ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { $t } from '#/locales';
const formData = ref<SystemRoleApi.SystemRole>();
const [Drawer] = useVbenDrawer({});
</script>
<template>
<Drawer />
</template>
研究过程不赘述 发现将schema改为内部(不引用data.ts) 则不报错
js
原版 从外部data.ts导入 报错
const [Form, formApi] = useVbenForm({
schema: useFormSchema(),
showDefaultActions: false,
});
内部 不报错
const [Form, formApi] = useVbenForm({
schema: [],
showDefaultActions: false,
});
最终发现 只要把data.ts中引用的schema移动到新的ts 或者 直接在modal.vue 都能正常运行(算一种解决方案)
js
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
labelWidth: 80,
},
schema: [直接在这里写 不从data.ts导入],
showDefaultActions: false,
});
或者
js
// 跟data.ts文件分开
import { modalSchema } from './other';
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
labelWidth: 80,
},
schema: modalSchema(),
showDefaultActions: false,
});
这是一种解决方案 但不是最终的解决方案
另外的解决方案
使用热更新api来操作 也能正常 不推荐
html
<script setup lang="ts">
const key = ref(0);
if (import.meta.hot) {
import.meta.hot.accept(() => {
key.value++;
});
}
</script>
<template>
<BasicModal :key="key" :title="title" class="w-[550px]">
<BasicForm />
</BasicModal>
</template>
继续分析
问题跟useForm也无关 去除form后保存data.ts 热更新还是报错 那么问题就是在modal(drawer)上
那么需要确定是modal造成的还是useVbenModal造成
使用控制变量的方法 直接不使用useVbenModal方法 导入modal并且更改props来直接显示
bash
packages/@core/ui-kit/popup-ui/src/modal/modal.vue
发现保存 热更新也是在报错 那么确定就是组件的问题
通过一个个删除元素 最终确认!!!
问题出在这个组件 DialogContent!!!

内部是这个组件 radix-vue提供的DialogPortal 确认是这个组件产生的问题

只要这个删除(换成div) 热更新就不会报错(当然样式也会有异常)
到github查看源码

使用的是TeleportPrimitive 问题出在这里 查看源码

贴上关键代码
js
<script setup lang="ts">
import { useMounted } from '@vueuse/core'
withDefaults(defineProps<TeleportProps>(), {
to: 'body',
})
const isMounted = useMounted()
</script>
<template>
<Teleport
v-if="isMounted || forceMount"
:to="to"
:disabled="disabled"
:defer="defer"
>
<slot />
</Teleport>
</template>
本质就是对Teleport的封装(且参数都和Vue的一致) 看起来也没啥问题 那直接把上面的组件换成vue的Teleport试试 发现
热更新正常了 不会报错了!!!
而且外部只使用了to参数 切换到teleport也是无缝

after

经过测试 热更新不会出现问题
原因分析
将文件粘贴到本地来测试

DialogContent.vue 引用 DialogPortal.vue 引用 MyTeleport.vue
保存 果然出现了问题

然后直接引用MyTeleport.vue来测试

也报错

当直接使用Teleport是正常了 只要包装了一层 就会产生问题
目前看使用Teleport替换也没有产生什么副作用 先这样吧 有空再分析补充
解决方案
packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogContent.vue
将DialogPortal替换为Teleport
Drawer也是一样的改法
packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetContent.vue
将DialogPortal替换为Teleport