Skip to content

Commit 27724f3

Browse files
committed
#7076 WIP
1 parent b29371b commit 27724f3

2 files changed

Lines changed: 37 additions & 26 deletions

File tree

.github/ticket-asymmetric-vdom-updates.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ This feature branch represents a major architectural enhancement to the VDOM upd
9999

100100
- **Core Framework Refactoring:**
101101
- `mixin/VdomLifecycle.mjs`: This critical mixin has been significantly refactored. The complex, distributed state management (`childUpdateCache`) has been removed, and it now delegates all collision and merge logic to the new `VDomUpdate` manager.
102+
The `executeVdomUpdate()` method has been modernized to use `async/await`, making the control flow more robust and readable, and ensuring deltas are correctly applied in non-worker environments.
102103
- `vdom/Helper.mjs`: The diffing engine has been enhanced to support the new asymmetric update strategy.
103104
- `component/Base.mjs`: The base component has been improved with a robust `mountedPromise` for easier async handling and other lifecycle enhancements to support the new update model.
104105
- `manager/Component.mjs`: Has undergone significant refactoring to align with the new VDOM strategies.
@@ -112,8 +113,10 @@ This feature branch represents a major architectural enhancement to the VDOM upd
112113

113114
### Remaining Work to Complete the Epic (as of this PR)
114115

115-
The `dev` branch still contains the original, distributed state management logic within `VdomLifecycle.mjs`. The following work remains to be done on this feature branch before it can be merged:
116+
While the core architectural shift is complete, the following tasks remain to finalize the epic:
116117

117-
- **Full Integration:** Refactor `VdomLifecycle.mjs` to completely remove its local caches and delegate all collision and merge logic to the new `VDomUpdate` manager.
118-
- **Finalize Asymmetric Logic:** Complete the implementation in `TreeBuilder` and `vdom.Helper` to handle the `neo-ignore` placeholder for truly asymmetric updates.
118+
- **Finalize Cleanup:**
119+
- The `childUpdateCache` property inside `src/component/Base.mjs` is now obsolete. It can be safely removed, as `VDomUpdate` has taken over its responsibilities.
120+
- The `updateVdom()` method in `VdomLifecycle.mjs` still uses a `timeout` to handle updates on unmounted components. This can be refactored to use the new `mountedPromise`, creating a cleaner and more robust implementation.
121+
- **Complete Asymmetric Logic:** The `TreeBuilder` and `vdom.Helper` still need the final logic to handle the `neo-ignore` placeholder. This will enable truly asymmetric updates where non-participating component sub-trees are completely skipped during the diffing process.
119122
- **Performance Benchmarking:** Conduct rigorous performance tests to compare this branch against `dev` and ensure no regressions.

src/util/vdom/TreeBuilder.mjs

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ class TreeBuilder extends Base {
3434
*/
3535
getVdomTree(vdom, depth = -1, mergedChildIds = null) {
3636
if (!Neo.isObject(vdom)) {
37-
return vdom;
37+
return vdom
3838
}
3939

40-
let output = {...vdom}, // shallow copy
40+
let output = {...vdom}, // Shallow copy
4141
childDepth;
4242

4343
if (vdom.cn) {
@@ -47,24 +47,28 @@ class TreeBuilder extends Base {
4747
let currentItem = item;
4848

4949
if (currentItem.componentId) {
50-
// A component placeholder is expanded if depth is -1 (full tree) or if
51-
// the current expansion depth is greater than 1.
52-
if (depth === -1 || depth > 1) {
50+
// Prune the branch only if we are at the boundary AND the child is not part of a merged update
51+
if (depth === 1 && !mergedChildIds?.has(currentItem.componentId)) {
52+
currentItem = {componentId: 'neo-ignore', id: currentItem.id}
53+
}
54+
// Expand the branch if it's part of a merged update, or if the depth requires it
55+
else if (depth > 1 || depth === -1 || mergedChildIds?.has(currentItem.componentId)) {
5356
const component = ComponentManager.get(currentItem.componentId);
5457
if (component?.vdom) {
55-
currentItem = component.vdom;
58+
currentItem = component.vdom
5659
}
5760
}
5861
}
5962

60-
if (item.componentId) { // check original item
61-
childDepth = (depth === -1) ? -1 : Math.max(0, depth - 1);
63+
// Check original item
64+
if (item.componentId) {
65+
childDepth = (depth === -1) ? -1 : Math.max(0, depth - 1)
6266
} else {
63-
childDepth = depth;
67+
childDepth = depth
6468
}
6569

66-
output.cn.push(this.getVdomTree(currentItem, childDepth, mergedChildIds));
67-
});
70+
output.cn.push(this.getVdomTree(currentItem, childDepth, mergedChildIds))
71+
})
6872
}
6973

7074
return output
@@ -80,7 +84,7 @@ class TreeBuilder extends Base {
8084
* @returns {Object}
8185
*/
8286
getVnodeTree(vnode, depth = -1, mergedChildIds = null) {
83-
let output = {...vnode}, // shallow copy
87+
let output = {...vnode}, // Shallow copy
8488
childDepth, component;
8589

8690
if (vnode.childNodes) {
@@ -90,30 +94,34 @@ class TreeBuilder extends Base {
9094
let currentItem = item;
9195

9296
if (currentItem.componentId) {
93-
// A component placeholder is expanded if depth is -1 (full tree) or if
94-
// the current expansion depth is greater than 1.
95-
if (depth === -1 || depth > 1) {
97+
// Prune the branch only if we are at the boundary AND the child is not part of a merged update
98+
if (depth === 1 && !mergedChildIds?.has(currentItem.componentId)) {
99+
currentItem = {componentId: 'neo-ignore', id: currentItem.id}
100+
}
101+
// Expand the branch if it's part of a merged update, or if the depth requires it
102+
else if (depth > 1 || depth === -1 || mergedChildIds?.has(currentItem.componentId)) {
96103
component = ComponentManager.get(currentItem.componentId);
97104

98-
// keep references in case there is no vnode (e.g. component not mounted yet)
105+
// Keep references in case there is no vnode (e.g. component not mounted yet)
99106
if (component?.vnode) {
100-
currentItem = component.vnode;
107+
currentItem = component.vnode
101108
}
102109
}
103110
}
104111

105-
if (item.componentId) { // check original item
106-
childDepth = (depth === -1) ? -1 : Math.max(0, depth - 1);
112+
// Check original item
113+
if (item.componentId) {
114+
childDepth = (depth === -1) ? -1 : Math.max(0, depth - 1)
107115
} else {
108-
childDepth = depth;
116+
childDepth = depth
109117
}
110118

111-
output.childNodes.push(this.getVnodeTree(currentItem, childDepth, mergedChildIds));
112-
});
119+
output.childNodes.push(this.getVnodeTree(currentItem, childDepth, mergedChildIds))
120+
})
113121
}
114122

115123
return output
116124
}
117125
}
118126

119-
export default Neo.setupClass(TreeBuilder);
127+
export default Neo.setupClass(TreeBuilder);

0 commit comments

Comments
 (0)