Skip to content

Fix morphBetween always using cloneNode even when node is detached - #4923

Open
ghabriel25 wants to merge 4 commits into
alpinejs:mainfrom
ghabriel25:fix/morph-between
Open

ghabriel25 wants to merge 4 commits into
alpinejs:mainfrom
ghabriel25:fix/morph-between

Conversation

@ghabriel25

@ghabriel25 ghabriel25 commented Sep 30, 2026 •

Copy link
Copy Markdown

Summary

Fixes duplicate media resource loads (e.g. <video> / <source>) when morphing detached HTML trees through morph / morphBetween.

Alpine always used node.cloneNode(true) when inserting nodes from the “to” tree. For detached morph blueprints that duplicates media elements, this can trigger a second network fetch (notably with Livewire deferred islands — livewire/livewire#10763).

Root cause

In addNodeBefore, the empty-from append path, and swapElements, the implementation did:

let clone = node.cloneNode(true)
parent.insertBefore(clone, beforeMe)

The live DOM always received a clone of the temporary to-tree. Media elements in that clone start resource selection again, so the same asset can load twice.

Passing a string vs a pre-built element does not matter: both end in the same clone path.

Solution

Introduce transferNode:

  • !node.isConnected (detached morph blueprint) → move the node (no second media element)
  • node.isConnected (live node used as “to”) → cloneNode(true) (do not steal it from the document)

Apply transferNode only where the to-node is not needed again as a blueprint in the same step:

Path Behavior
swapElements transferNode
Empty from append transferNode
addNodeBefore Always cloneNode(true)

addNodeBefore still clones because lookahead can insert then fall through to patch(currentFrom, currentTo). Moving currentTo there would make patch run against the same node.

When moving is possible, capture the next “to” sibling before the move so the to-walk stays valid:

while (currentTo) {
    let nextTo = getNextSibling(to, currentTo)
    // ...
    currentTo = nextTo
}
Before After
bug bug1

Fixes: livewire/livewire#10763

@ghabriel25 ghabriel25 changed the title Fix morphBetween always using cloneNode even node is detached Fix morphBetween always using cloneNode even when node is detached Sep 30, 2026
@ghabriel25
ghabriel25 marked this pull request as ready for review September 30, 2026 16:41

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Island defer loads twice video asset

1 participant