From 8b6c31c4efac250400e00a75bb937e19e1f6257e Mon Sep 17 00:00:00 2001 From: Caleb Porzio Date: Thu, 28 Nov 2024 10:23:53 -0500 Subject: [PATCH] Optimize mutation observer to better handle move operations - ref #4450 --- index.html | 30 +++++++++++++++++++----------- packages/alpinejs/src/mutation.js | 20 +++++++++++++++++--- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/index.html b/index.html index 376da39f0..7148e70a6 100644 --- a/index.html +++ b/index.html @@ -11,17 +11,25 @@ -
-
foo
-
foo
-
foo
-
+ +
+
+ +
-
- - - - +
diff --git a/packages/alpinejs/src/mutation.js b/packages/alpinejs/src/mutation.js index e39abb129..363e17b9c 100644 --- a/packages/alpinejs/src/mutation.js +++ b/packages/alpinejs/src/mutation.js @@ -112,6 +112,8 @@ export function flushAndStopDeferringMutations() { } function onMutate(mutations) { + console.log(mutations); + if (isCollecting) { deferredMutations = deferredMutations.concat(mutations) @@ -119,7 +121,7 @@ function onMutate(mutations) { } let addedNodes = [] - let removedNodes = [] + let removedNodes = new Set let addedAttributes = new Map let removedAttributes = new Map @@ -129,14 +131,26 @@ function onMutate(mutations) { if (mutations[i].type === 'childList') { mutations[i].removedNodes.forEach(node => { if (node.nodeType !== 1) return + + // No need to process removed nodes that haven't been initialized by Alpine... if (! node._x_marker) return - removedNodes.push(node) + removedNodes.add(node) }) mutations[i].addedNodes.forEach(node => { if (node.nodeType !== 1) return + // If the node is a removal as well, that means it's a "move" operation and we'll leave it alone... + if (removedNodes.has(node)) { + removedNodes.delete(node) + + return + } + + // If the node has already been initialized, we'll leave it alone... + if (node._x_marker) return; + addedNodes.push(node) }) } @@ -197,7 +211,7 @@ function onMutate(mutations) { for (let node of addedNodes) { if (! node.isConnected) continue - if (node._x_marker) return; + onElAddeds.forEach(i => i(node)) }