Comfy-Org / Comfy-Org/ComfyUI_frontend
[Bug]: Custom sidebar extensions not properly destroyed when switching tabs
- Dominant language
- TypeScript
- Stars
- 2k
- Forks
- 699
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 490
Description
## Preliminary Checks
- [x] This bug report is for the latest version of ComfyUI frontend
- [x] There are no existing bug reports for this issue
- [x] This issue persists when all custom nodes are disabled
## What is the expected behavior?
When switching between sidebar tabs, custom extensions should have their `destroy()` method called to properly clean up resources, unmount components, and reset state - similar to how Vue components are automatically cleaned up.
## What is the actual behavior?
Custom sidebar extensions are **not** properly destroyed when switching between tabs. The `destroy()` method is only called when:
1. The custom tab is currently active AND the entire sidebar is closed
2. Never called when switching from a custom tab to another tab (built-in or custom)
This causes custom extensions to remain mounted and visible when they should be hidden, leading to UI overlap and resource leaks.
## Steps to reproduce
1. Install a custom sidebar extension (e.g., ComfyUI-React-Extension-Template)
2. Open the custom extension tab in the sidebar
3. Switch to another sidebar tab (Queue, Node Library, etc.)
4. **Expected**: Custom extension should disappear/be destroyed
5. **Actual**: Custom extension remains visible and overlaps with the new tab
## Additional testing showing the inconsistency:
- ✅ **Built-in tabs**: Properly hide when switching (Queue → Node Library works correctly)
- ❌ **Custom → Built-in**: Custom extension remains visible
- ❌ **Custom → Custom**: Both extensions visible simultaneously
- ❌ **Built-in → Custom**: Custom extension shows but built-in doesn't properly hide
## Root Cause Analysis
The issue is in `SideToolbar.vue` and `ExtensionSlot.vue`:
**Current code in SideToolbar.vue:**
```vue
```
**Problem**: When `selectedTab` changes from `tab1` to `tab2`, Vue **updates** the `ExtensionSlot` component props but doesn't **unmount** it. Therefore `onBeforeUnmount` in `ExtensionSlot.vue` is never triggered, and the previous extension's `destroy()` method is never called.
## Proposed Fix
Add a `key` attribute to force Vue to unmount/remount the ExtensionSlot when the extension changes:
```vue
```
This ensures:
1. Old ExtensionSlot is unmounted (triggering `onBeforeUnmount` → `destroy()`)
2. New ExtensionSlot is mounted with fresh state
3. Proper cleanup of custom extension resources
## Debug Logs
Custom extension logging shows:
```
[React Extension] render() called
[React Extension] Registering sidebar tab with ComfyUI
[React Extension] Sidebar tab registered successfully
// ... switching tabs ...
// destroy() is NEVER called unless sidebar is closed while custom tab is active
```
## Environment
- **Frontend Version**: Latest (main branch)
- **Browser**: Multiple browsers affected
- **Custom Extension**: ComfyUI-React-Extension-Template (and affects all custom sidebar extensions)
## Impact
This bug affects all custom sidebar extensions and causes:
- Visual overlap of UI components
- Memory leaks from unclean component unmounting
- Event listeners not being properly removed
- Inconsistent UX compared to built-in tabs
## Related Issues
This may be related to the general sidebar management system and could affect:
- Issue #3635: Secondary sidebar extensions
- Future custom extension development
## Testing
This issue can be reproduced with any custom sidebar extension. The ComfyUI-React-Extension-Template provides a good test case as it demonstrates the expected `render()`/`destroy()` lifecycle pattern.
┆Issue is synchronized with this [Notion page](https://www.notion.so/Issue-4372-Bug-Custom-sidebar-extensions-not-properly-destroyed-when-switching-tabs-2296d73d36508133a781c8b0630729eb) by [Unito](https://www.unito.io)
Contributor guide
Assessment
This issue has not been assessed yet.