Skip to content

Commit

Permalink
insertBefore bugfix
Browse files Browse the repository at this point in the history
  • Loading branch information
Thunberg087 committed May 31, 2022
1 parent f1ebaca commit 82937dc
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 8 deletions.
6 changes: 3 additions & 3 deletions src/component.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const freeze = (object, property, value) => {
export const freeze = (object, property, value) => {
Object.defineProperty(object, property, {
configurable: true,
get() { return value; },
set(v) { console.warn(`tried to set frozen property ${property} with ${v}`) }
});
};

const unfreeze = (object, property, value = null) => {
export const unfreeze = (object, property, value = null) => {
Object.defineProperty(object, property, {
configurable: true,
writable: true,
Expand Down Expand Up @@ -45,7 +45,7 @@ export default {
// use document fragment to improve efficiency
let tpl = document.createDocumentFragment()
tpl.appendChild(head)

Array.from(container.childNodes)
.forEach(node => {
// container.appendChild(node, true)
Expand Down
98 changes: 93 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,104 @@
import component from './component'
import ssr from './ssr'
import component, { freeze, unfreeze } from './component'
import ssr from './ssr'

export const Fragment = component

export const SSR = ssr

export const Plugin = {
install: function(Vue) {
install: function (Vue) {
const orgRemoveChild = window.Node.prototype.removeChild

This comment has been minimized.

Copy link
@jamsch

jamsch Jun 8, 2022

This breaks in SSR frameworks like Nuxt, since window isn't defined outside the browser context. I'd add a check here to make sure that window is defined.

This comment has been minimized.

Copy link
@sonnh58

sonnh58 Jan 5, 2023

same issue

window.Node.prototype.removeChild = function (node) {
if (this.__isFragment) {
if (this.parentNode) {
let ret = this.parentNode.removeChild(node)
unfreeze(node, 'parentNode')
return ret
}
} else if (node.__isFragment && node.__isMounted) {
while (node.__head.nextSibling !== node.__tail) orgRemoveChild.call(this, node.__head.nextSibling)

orgRemoveChild.call(this, node.__head)
orgRemoveChild.call(this, node.__tail)
let prev = node.__head.previousSibling,
next = node.__tail.nextSibling
if (prev) freeze(prev, 'nextSibling', next)
if (next) freeze(next, 'previousSibling', prev)

unfreeze(node, 'parentNode')
return node
} else {
let prev = node.previousSibling,
next = node.nextSibling
let ret = orgRemoveChild.call(this, node)
if (prev) freeze(prev, 'nextSibling', next)
if (next) freeze(next, 'previousSibling', prev)
return ret
}
}

const orgInsertBefore = window.Node.prototype.insertBefore
window.Node.prototype.insertBefore = function (node, ref, inFragment = false) {
let realRef = !!ref && !!ref.__isFragment && !!ref.__isMounted ? ref.__head : ref
if (this.__isFragment) {
let notFrChild = !node.hasOwnProperty('__isFragmentChild__'),
freezeParent = !inFragment || notFrChild

notFrChild && freeze(node, '__isFragmentChild__', true)
let ret = this.parentNode ? this.parentNode.insertBefore(node, ref) : orgInsertBefore.call(this, node, realRef)
freezeParent && freeze(node, 'parentNode', this)

return ret
} else if (node.__isFragment && node.__isMounted) {
if (node === ref) {
console.error('something must be wrong')
return
}
freeze(node, 'parentNode', this)
if (node.previousSibling) freeze(node.previousSibling, 'nextSibling', node.nextSibling)
if (node.nextSibling) freeze(node.nextSibling, 'previousSibling', node.previousSibling)
freeze(node, 'nextSibling', ref)
freeze(node, 'previousSibling', ref.previousSibling)
if (ref.previousSibling) freeze(ref.previousSibling, 'nextSibling', node)
freeze(ref, 'previousSibling', node)

let tpl = document.createDocumentFragment(),
ele = node.__head
while (ele !== node.__tail) {
tpl.appendChild(ele)
ele = ele.nextSibling
}
tpl.appendChild(node.__tail)
orgInsertBefore.call(this, tpl, realRef)
return node
} else {
return orgInsertBefore.call(this, node, realRef)
}
}

const orgAppendChild = window.Node.prototype.appendChild
window.Node.prototype.appendChild = function (node, inFragment = false) {
if (this.__isFragment) {
if (this.parentNode) {
let notFrChild = !node.hasOwnProperty('__isFragmentChild__'),
freezeParent = !inFragment || notFrChild

notFrChild && freeze(node, '__isFragmentChild__', true)
let ret = this.parentNode.insertBefore(node, this.__tail, inFragment)
freezeParent && freeze(node, 'parentNode', this)

return ret
}
} else {
return orgAppendChild.call(this, node)
}
}
Vue.component('Fragment', component)
}
},
}

export default {
Fragment, Plugin, SSR
Fragment,
Plugin,
SSR,
}

0 comments on commit 82937dc

Please sign in to comment.