Skip to content

Commit

Permalink
Speed up patching 5-10x (#2845)
Browse files Browse the repository at this point in the history
Co-authored-by: José Valim <[email protected]>
  • Loading branch information
chrismccord and josevalim committed Oct 13, 2023
1 parent b2c8999 commit bed2ff0
Show file tree
Hide file tree
Showing 16 changed files with 920 additions and 539 deletions.
4 changes: 3 additions & 1 deletion assets/js/phoenix_live_view/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const PHX_DROP_TARGET = "drop-target"
export const PHX_ACTIVE_ENTRY_REFS = "data-phx-active-refs"
export const PHX_LIVE_FILE_UPDATED = "phx:live-file:updated"
export const PHX_SKIP = "data-phx-skip"
export const PHX_MAGIC_ID = "data-phx-id"
export const PHX_PRUNE = "data-phx-prune"
export const PHX_PAGE_LOADING = "page-loading"
export const PHX_CONNECTED_CLASS = "phx-connected"
Expand Down Expand Up @@ -79,9 +80,10 @@ export const DEFAULTS = {
// Rendered
export const DYNAMICS = "d"
export const STATIC = "s"
export const ROOT = "r"
export const COMPONENTS = "c"
export const EVENTS = "e"
export const REPLY = "r"
export const TITLE = "t"
export const TEMPLATES = "p"
export const STREAM = "stream"
export const STREAM = "stream"
46 changes: 6 additions & 40 deletions assets/js/phoenix_live_view/dom_patch.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
PHX_ROOT_ID,
PHX_SESSION,
PHX_SKIP,
PHX_MAGIC_ID,
PHX_STATIC,
PHX_TRIGGER_ACTION,
PHX_UPDATE,
Expand Down Expand Up @@ -96,10 +97,6 @@ export default class DOMPatch {

let externalFormTriggered = null

let diffHTML = liveSocket.time("premorph container prep", () => {
return this.buildDiffHTML(container, html, phxUpdate, targetContainer)
})

this.trackBefore("added", container)
this.trackBefore("updated", container, container)

Expand All @@ -121,10 +118,11 @@ export default class DOMPatch {
})
})

morphdom(targetContainer, diffHTML, {
morphdom(targetContainer, html, {
childrenOnly: targetContainer.getAttribute(PHX_COMPONENT) === null,
getNodeKey: (node) => {
return DOM.isPhxDestroyed(node) ? null : node.id
if(DOM.isPhxDestroyed(node)){ return null }
return (node.getAttribute && node.getAttribute(PHX_MAGIC_ID)) || node.id
},
// skip indexing from children when container is stream
skipFromChildren: (from) => { return from.getAttribute(phxUpdate) === PHX_STREAM },
Expand Down Expand Up @@ -363,7 +361,7 @@ export default class DOMPatch {
isCIDPatch(){ return this.cidPatch }

skipCIDSibling(el){
return el.nodeType === Node.ELEMENT_NODE && el.getAttribute(PHX_SKIP) !== null
return el.nodeType === Node.ELEMENT_NODE && el.hasAttribute(PHX_SKIP)
}

targetCIDContainer(html){
Expand All @@ -376,37 +374,5 @@ export default class DOMPatch {
}
}

// builds HTML for morphdom patch
// - for full patches of LiveView or a component with a single
// root node, simply returns the HTML
// - for patches of a component with multiple root nodes, the
// parent node becomes the target container and non-component
// siblings are marked as skip.
buildDiffHTML(container, html, phxUpdate, targetContainer){
let isCIDPatch = this.isCIDPatch()
let isCIDWithSingleRoot = isCIDPatch && targetContainer.getAttribute(PHX_COMPONENT) === this.targetCID.toString()
if(!isCIDPatch || isCIDWithSingleRoot){
return html
} else {
// component patch with multiple CID roots
let diffContainer = null
let template = document.createElement("template")
diffContainer = DOM.cloneNode(targetContainer)
let [firstComponent, ...rest] = DOM.findComponentNodeList(diffContainer, this.targetCID)
template.innerHTML = html
rest.forEach(el => el.remove())
Array.from(diffContainer.childNodes).forEach(child => {
// we can only skip trackable nodes with an ID
if(child.id && child.nodeType === Node.ELEMENT_NODE && child.getAttribute(PHX_COMPONENT) !== this.targetCID.toString()){
child.setAttribute(PHX_SKIP, "")
child.innerHTML = ""
}
})
Array.from(template.content.childNodes).forEach(el => diffContainer.insertBefore(el, firstComponent))
firstComponent.remove()
return diffContainer.outerHTML
}
}

indexOf(parent, child){ return Array.from(parent.children).indexOf(child) }
}
}
Loading

0 comments on commit bed2ff0

Please sign in to comment.