From 51ab1541dda9077bcbf1e003e03082c01b7a2526 Mon Sep 17 00:00:00 2001 From: Johnpaul Date: Thu, 27 Nov 2025 04:06:19 +0100 Subject: [PATCH] fix: properly cleanup video event listeners on unmount - Store cleanup function reference for pending video event listeners - Call cleanup in onUnmounted to prevent memory leaks if component unmounts while waiting for video metadata --- .../widgets/components/WidgetWebcam.vue | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue b/src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue index cd5d0f009..e15573c42 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue +++ b/src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue @@ -100,6 +100,8 @@ const originalWidgets = ref([]) const videoRef = ref() const videoContainerRef = ref() const stream = ref(null) +// Track pending video event listeners for cleanup +const pendingVideoCleanup = ref<(() => void) | null>(null) const isHovered = useElementHover(videoContainerRef) const canvas = document.createElement('canvas') // Persistent video element for capture - not in DOM template but keeps stream active @@ -602,22 +604,30 @@ async function startCameraPreview() { const video = videoRef.value - const onLoadedMetadata = () => { + const cleanup = () => { video.removeEventListener('loadedmetadata', onLoadedMetadata) + video.removeEventListener('error', onError) + pendingVideoCleanup.value = null + } + + const onLoadedMetadata = () => { + cleanup() resolve() } const onError = (error: Event) => { - video.removeEventListener('error', onError) + cleanup() reject(error) } video.addEventListener('loadedmetadata', onLoadedMetadata) video.addEventListener('error', onError) + // Store cleanup function for onUnmounted + pendingVideoCleanup.value = cleanup + setTimeout(() => { - video.removeEventListener('loadedmetadata', onLoadedMetadata) - video.removeEventListener('error', onError) + cleanup() resolve() }, 1000) }) @@ -677,6 +687,8 @@ onMounted(async () => { }) onUnmounted(() => { + // Clean up any pending video event listeners + pendingVideoCleanup.value?.() stopStreamTracks() restoreWidgets() })