关于 Vben5 热更新 Cannot read properties of null (reading 'nextSibling')的分析

问题

保存时仍需报错 但是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查看源码

github.com/unovue/reka...

使用的是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

相关推荐
傻瓜搬砖人11 分钟前
SpringMVC的请求
java·前端·javascript·spring
爱上好庆祝25 分钟前
学习js的第六天(js基础的结束)
开发语言·前端·javascript·学习·ecmascript
IT_陈寒36 分钟前
JavaScript的异步地狱,我差点没爬出来
前端·人工智能·后端
光影少年36 分钟前
Webpack打包性能优化方面的经验
前端·webpack·性能优化
Das143 分钟前
通过命令行下载kaggle数据
前端·chrome
剑神一笑1 小时前
CSS Animation Timeline 可视化动画编辑器:从关键帧到流畅动画
前端·css·编辑器
Dylan的码园1 小时前
springBoot与Web后端基础
前端·spring boot·后端
广州华水科技1 小时前
单北斗变形监测应用于水库的精准GNSS技术解析
前端
2401_878454532 小时前
HTML和CSS的复习2
前端·css·html
We་ct2 小时前
吃透现代CSS全技术体系
前端·css·css3·sass·postcss·预处理器