mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-20 06:44:32 +00:00
refactor: migrate ES private fields to TypeScript private for Vue Proxy compatibility (#8440)
## Summary Migrates ECMAScript private fields (`#`) to TypeScript private (`private`) across LiteGraph to fix Vue Proxy reactivity incompatibility. ## Problem ES private fields (`#field`) are incompatible with Vue's Proxy-based reactivity system - accessing `#field` through a Proxy throws `TypeError: Cannot read private member from an object whose class did not declare it`. ## Solution - Converted all `#field` to `private _field` across 10 phases - Added `toJSON()` methods to `LGraph`, `NodeSlot`, `NodeInputSlot`, and `NodeOutputSlot` to prevent circular reference errors during serialization (TypeScript private fields are visible to `JSON.stringify` unlike true ES private fields) - Made `DragAndScale.element.data` non-enumerable to break canvas circular reference chain ## Testing - All 4027 unit tests pass - Added 9 new serialization tests to catch future circular reference issues - Browser tests (undo/redo, save workflows) verified working ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8440-refactor-migrate-ES-private-fields-to-TypeScript-private-for-Vue-Proxy-compatibility-2f76d73d365081a3bd82d429a3e0fcb7) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -241,17 +241,17 @@ function dragElement(dragEl): () => void {
|
||||
}
|
||||
|
||||
class ComfyList {
|
||||
#type
|
||||
#text
|
||||
#reverse
|
||||
private _type
|
||||
private _text
|
||||
private _reverse
|
||||
element: HTMLDivElement
|
||||
button?: HTMLButtonElement
|
||||
|
||||
// @ts-expect-error fixme ts strict error
|
||||
constructor(text, type?, reverse?) {
|
||||
this.#text = text
|
||||
this.#type = type || text.toLowerCase()
|
||||
this.#reverse = reverse || false
|
||||
this._text = text
|
||||
this._type = type || text.toLowerCase()
|
||||
this._reverse = reverse || false
|
||||
this.element = $el('div.comfy-list') as HTMLDivElement
|
||||
this.element.style.display = 'none'
|
||||
}
|
||||
@@ -261,7 +261,7 @@ class ComfyList {
|
||||
}
|
||||
|
||||
async load() {
|
||||
const items = await api.getItems(this.#type)
|
||||
const items = await api.getItems(this._type)
|
||||
this.element.replaceChildren(
|
||||
...Object.keys(items).flatMap((section) => [
|
||||
$el('h4', {
|
||||
@@ -269,12 +269,12 @@ class ComfyList {
|
||||
}),
|
||||
$el('div.comfy-list-items', [
|
||||
// @ts-expect-error fixme ts strict error
|
||||
...(this.#reverse ? items[section].reverse() : items[section]).map(
|
||||
...(this._reverse ? items[section].reverse() : items[section]).map(
|
||||
(item: LegacyQueueItem) => {
|
||||
// Allow items to specify a custom remove action (e.g. for interrupt current prompt)
|
||||
const removeAction = item.remove ?? {
|
||||
name: 'Delete',
|
||||
cb: () => api.deleteItem(this.#type, item.prompt[1])
|
||||
cb: () => api.deleteItem(this._type, item.prompt[1])
|
||||
}
|
||||
return $el('div', { textContent: item.prompt[0] + ': ' }, [
|
||||
$el('button', {
|
||||
@@ -311,9 +311,9 @@ class ComfyList {
|
||||
]),
|
||||
$el('div.comfy-list-actions', [
|
||||
$el('button', {
|
||||
textContent: 'Clear ' + this.#text,
|
||||
textContent: 'Clear ' + this._text,
|
||||
onclick: async () => {
|
||||
await api.clearItems(this.#type)
|
||||
await api.clearItems(this._type)
|
||||
await this.load()
|
||||
}
|
||||
}),
|
||||
@@ -339,7 +339,7 @@ class ComfyList {
|
||||
hide() {
|
||||
this.element.style.display = 'none'
|
||||
// @ts-expect-error fixme ts strict error
|
||||
this.button.textContent = 'View ' + this.#text
|
||||
this.button.textContent = 'View ' + this._text
|
||||
}
|
||||
|
||||
toggle() {
|
||||
|
||||
Reference in New Issue
Block a user