mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-22 21:38:52 +00:00
Wraps `LGraphNode.configure()`'s widget-value restoration phase in a
hydration transaction (`beginHydration` / `commitHydration`), preventing
derived-state callbacks (e.g. CustomCombo's `updateCombo`) from firing
before all widget values are restored.
```mermaid
flowchart LR
subgraph core["Core Layer"]
LGN["LGraphNode.configure()"]
WVS["widgetValueStore"]
end
subgraph extensions["Extension Layer"]
CW["CustomCombo\n(customWidgets.ts)"]
PN["PrimitiveNode\n(widgetInputs.ts)"]
end
LGN -- "beginHydration /\ncommitHydration" --> WVS
CW -- "isHydrating() guard" --> WVS
CW -- "onHydrationComplete()" --> WVS
PN -- "serialize() override\npreserves widgets_values" --> LGN
```
```mermaid
sequenceDiagram
participant Caller as Paste / Load
participant Node as LGraphNode.configure()
participant Store as widgetValueStore
participant Widget as Widget Setters
participant Combo as CustomCombo.updateCombo
Caller->>Node: configure(serializedData)
Node->>Store: beginHydration(nodeId)
activate Store
Note over Store: hydratingNodes.add(nodeId)
loop For each widget
Node->>Widget: widget.value = restored_value
Widget->>Combo: updateCombo() triggered
Combo->>Store: isHydrating(nodeId)?
Store-->>Combo: true - early return
Note over Combo: Side effect suppressed
end
Node->>Node: onConfigure(info)
Note over Node: Extensions register onHydrationComplete callbacks
Node->>Store: commitHydration(nodeId)
Note over Store: hydratingNodes.delete(nodeId)
Store->>Combo: fire queued callbacks
Note over Combo: updateCombo() runs once with all values present
deactivate Store
```
```mermaid
flowchart TB
subgraph before["Before: Race Condition"]
direction TB
B1["configure starts"] --> B2["widget1.value = optionA"]
B2 --> B3["updateCombo fires immediately"]
B3 --> B4["values list incomplete,\ncomboWidget.value reset"]
B4 --> B5["widget2.value = optionB"]
B5 --> B6["updateCombo fires again"]
B6 --> B7["Combo has wrong value"]
end
subgraph after["After: Hydration Transaction"]
direction TB
A1["configure starts"] --> A2["beginHydration nodeId"]
A2 --> A3["widget1.value = optionA"]
A3 --> A4["updateCombo skipped"]
A4 --> A5["widget2.value = optionB"]
A5 --> A6["updateCombo skipped"]
A6 --> A7["commitHydration nodeId"]
A7 --> A8["updateCombo runs once,\nall values present"]
end
```
- **`LGraphNode.configure()`**: Wraps widget restoration + `onConfigure`
in `beginHydration`/`commitHydration` with `try/finally` for exception
safety
- **`PrimitiveNode.serialize()`**: Adds override to preserve
`widgets_values` when widgets are dynamically disconnected
- **`customWidgets.ts`**: Simplifies CustomCombo's `onConfigure` to use
`onHydrationComplete()` instead of manually managing hydration state
- **3 new tests**: Hydration transaction wrapping, `onHydrationComplete`
callback firing, and exception safety
Stacked on #10010. Implements Design A from the widget state
architecture RFC.
Architecture Decision Records
This directory contains Architecture Decision Records (ADRs) for the ComfyUI Frontend project.
What is an ADR?
An Architecture Decision Record captures an important architectural decision made along with its context and consequences. ADRs help future developers understand why certain decisions were made and provide a historical record of the project's evolution.
ADR Index
| ADR | Title | Status | Date |
|---|---|---|---|
| 0001 | Merge LiteGraph.js into ComfyUI Frontend | Accepted | 2025-08-05 |
| 0002 | Restructure as a Monorepo | Accepted | 2025-08-25 |
| 0003 | Centralized Layout Management with CRDT | Proposed | 2025-08-27 |
| 0004 | Fork PrimeVue UI Library | Rejected | 2025-08-27 |
| 0005 | Remove Import Map for Vue Extensions | Accepted | 2025-12-13 |
| 0006 | PrimitiveNode Copy/Paste Lifecycle | Proposed | 2026-02-22 |
| 0007 | NodeExecutionOutput Passthrough Schema | Accepted | 2026-03-11 |
| 0008 | Entity Component System | Proposed | 2026-03-23 |
Creating a New ADR
- Copy the template below
- Name it with the next number in sequence:
NNNN-descriptive-title.md - Fill in all sections
- Update this index
- Submit as part of your PR
ADR Template
# N. Title
Date: YYYY-MM-DD
## Status
[Proposed | Accepted | Rejected | Deprecated | Superseded by [ADR-NNNN](NNNN-title.md)]
## Context
Describe the issue that motivated this decision and any context that influences or constrains the decision.
- What is the problem?
- Why does it need to be solved?
- What forces are at play (technical, business, team)?
## Decision
Describe the decision that was made and the key points that led to it.
- What are we going to do?
- How will we do it?
- What alternatives were considered?
## Consequences
### Positive
- What becomes easier or better?
- What opportunities does this create?
### Negative
- What becomes harder or worse?
- What risks are we accepting?
- What technical debt might we incur?
## Notes
Optional section for additional information, references, or clarifications.
ADR Status Values
- Proposed: The decision is being discussed
- Accepted: The decision has been agreed upon
- Rejected: The decision was not accepted
- Deprecated: The decision is no longer relevant
- Superseded: The decision has been replaced by another ADR
Further Reading
- Documenting Architecture Decisions by Michael Nygard
- Architecture Decision Records - Collection of ADR resources