Create a gist now

Instantly share code, notes, and snippets.

Theoretical method for granular patching in Mithril. main.js accepts an old vnode and a new vnode which should replace it. In practice the current method is theoretically flawed because if the hot path to the patched node includes components, these will re-execute, nullifying the effect of hot-patching their current instances' subtree. The alter…
export default function * ancestors({parentNode}){
if(parentNode){
yield parentNode
yield * ancestors(parentNode)
}
}
export default x => (
Array.isArray(x)
? Array.from(x)
: Object.assign({}, x)
)
export default function find(predicate, iterator){
for(const item in iterator)
if(predicate(item))
return item
}
import clone from './clone.js'
import find from './find.js'
import ancestors from './ancestors.js'
import paths from './paths.js'
import vtraverse from './vtraverse.js'
import patch from './patch.js'
export default function merge(oldVnode, newVnode = clone(oldVnode)){
const root = find(({vnodes}) => Array.isArray(vnodes), ancestors(oldVnode.dom))
const base = root.vnodes
const {path} = find(({value}) => value === oldVnode, paths(vtraverse(base)))
const snapshot = patch(newVnode, path, base)
m.render(root, snapshot)
}
import clone from './clone.js'
export default function patch(leaf, path, base){
const output = clone(base)
const head = path.slice(0, path.length - 1)
const tail = path.slice(-1)
let node = output
for(const key of head){
node[key] = clone(node[key])
node = node[key]
}
node[tail] = leaf
return output
}
export default function * paths(iterator){
let path = []
for(const {depth, key, value} of iterator){
path = path.slice(0, depth + 1).concat(key)
yield {path, value}
}
}
export default function * vtraverse(vnode, depth = 0){
if(Array.isArray(vnode))
for(let index = 0; index < vnode.length; index++){
yield {value: vnode[index], key: index, depth}
yield * vtraverse(vnode[index], depth)
}
else if(vnode.instance){
yield {value: vnode.instance, key: 'instance', depth}
yield * vtraverse(vnode.instance, depth)
}
else if(vnode.children){
yield {value: vnode.children, key: 'children', depth}
yield * vtraverse(vnode.children, depth)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment