[feat] Update node output system to use NodeLocatorIds (#4500)

This commit is contained in:
Christian Byrne
2025-07-23 22:01:18 -07:00
committed by GitHub
parent 052d5320c0
commit c06bc63c6f
7 changed files with 961 additions and 52 deletions

View File

@@ -47,6 +47,7 @@ import { useDomWidgetStore } from '@/stores/domWidgetStore'
import { useExecutionStore } from '@/stores/executionStore'
import { useExtensionStore } from '@/stores/extensionStore'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useNodeOutputStore } from '@/stores/imagePreviewStore'
import { KeyComboImpl, useKeybindingStore } from '@/stores/keybindingStore'
import { useModelStore } from '@/stores/modelStore'
import { SYSTEM_NODE_DEFS, useNodeDefStore } from '@/stores/nodeDefStore'
@@ -60,6 +61,10 @@ import type { ComfyExtension, MissingNodeType } from '@/types/comfy'
import { ExtensionManager } from '@/types/extensionTypes'
import { ColorAdjustOptions, adjustColor } from '@/utils/colorUtil'
import { graphToPrompt } from '@/utils/executionUtil'
import {
getNodeByExecutionId,
triggerCallbackOnAllNodes
} from '@/utils/graphTraversalUtil'
import {
executeWidgetsCallback,
fixLinkInputSlots,
@@ -640,29 +645,21 @@ export class ComfyApp {
})
api.addEventListener('executed', ({ detail }) => {
const output = this.nodeOutputs[detail.display_node || detail.node]
if (detail.merge && output) {
for (const k in detail.output ?? {}) {
const v = output[k]
if (v instanceof Array) {
output[k] = v.concat(detail.output[k])
} else {
output[k] = detail.output[k]
}
}
} else {
this.nodeOutputs[detail.display_node || detail.node] = detail.output
}
const node = this.graph.getNodeById(detail.display_node || detail.node)
if (node) {
if (node.onExecuted) node.onExecuted(detail.output)
const nodeOutputStore = useNodeOutputStore()
const executionId = String(detail.display_node || detail.node)
nodeOutputStore.setNodeOutputsByExecutionId(executionId, detail.output, {
merge: detail.merge
})
const node = getNodeByExecutionId(this.graph, executionId)
if (node && node.onExecuted) {
node.onExecuted(detail.output)
}
})
api.addEventListener('execution_start', () => {
this.graph.nodes.forEach((node) => {
if (node.onExecutionStart) node.onExecutionStart()
})
triggerCallbackOnAllNodes(this.graph, 'onExecutionStart')
})
api.addEventListener('execution_error', ({ detail }) => {
@@ -690,11 +687,13 @@ export class ComfyApp {
api.addEventListener('b_preview_with_metadata', ({ detail }) => {
// Enhanced preview with explicit node context
const { blob, displayNodeId } = detail
const { setNodePreviewsByExecutionId, revokePreviewsByExecutionId } =
useNodeOutputStore()
// Ensure clean up if `executing` event is missed.
this.revokePreviews(displayNodeId)
revokePreviewsByExecutionId(displayNodeId)
const blobUrl = URL.createObjectURL(blob)
// Preview cleanup is now handled in progress_state event to support multiple concurrent previews
this.nodePreviewImages[displayNodeId] = [blobUrl]
// Preview cleanup is handled in progress_state event to support multiple concurrent previews
setNodePreviewsByExecutionId(displayNodeId, [blobUrl])
})
api.init()
@@ -1673,25 +1672,13 @@ export class ComfyApp {
}
}
/**
* Frees memory allocated to image preview blobs for a specific node, by revoking the URLs associated with them.
* @param nodeId ID of the node to revoke all preview images of
*/
revokePreviews(nodeId: NodeId) {
if (!this.nodePreviewImages[nodeId]?.[Symbol.iterator]) return
for (const url of this.nodePreviewImages[nodeId]) {
URL.revokeObjectURL(url)
}
}
/**
* Clean current state
*/
clean() {
this.nodeOutputs = {}
for (const id of Object.keys(this.nodePreviewImages)) {
this.revokePreviews(id)
}
this.nodePreviewImages = {}
const { revokeAllPreviews } = useNodeOutputStore()
revokeAllPreviews()
const executionStore = useExecutionStore()
executionStore.lastNodeErrors = null
executionStore.lastExecutionError = null