yelouafi / petit-dom

minimalist virtual dom library
MIT License
506 stars 36 forks source link

New DOM-tree is not synced with vdom-tree, leads to exception. #27

Closed cjh9 closed 5 years ago

cjh9 commented 5 years ago

Hi! I might found another bug, I still get "Failed to execute 'replaceChild' on 'Node': The node to be replaced is not a child of this node." sometimes, and I think that this time it is because to the vdom-tree is not the same as the DOM-tree after a patch. Take a look at this example:

<body>
    <div id="app-root"></div>
    <script type="module">
    import {h, patch, mount} from 'https://unpkg.com/petit-dom?module'

    var oldVnode = 
    h('div', {}, [
        h('p', {}, [
            'Text',
            h('code', {}, ['Text']),'Text',
            h('code', {}, ['Text']),'Text'
        ]),
        h('div', {}, [])
    ])

    var newVnode = 
    h('div', {}, [
        h('p', {}, [
            h('a', {}, ['Text'])
        ]),
        'Text',
        h('p', {}, [
            h('a', {}, ['Text'])
        ]),
        'Text',
        h('p', {}, [
            'Text',
            h('a', {}, ['Text']),
            'Text'
        ]),
        h('div', {}, [])
    ])

    document.querySelector('#app-root').appendChild(mount(oldVnode))

    patch(newVnode, oldVnode)

    /* Will render this as HTML, the first "code" should be a "link tag"

        <div>
            <p>
                <code>Text</code>
            </p>
            Text
            <p>
                <a>Text</a>
            </p>
            Text
            <p>
                Text
                <a>Text</a>
                Text
            </p>
            <div></div>
        </div>

    */

    function checkSimlilarity(vdomNode, domnode){
        if(domnode.nodeType === 3) {
            const textErr = domnode.textContent !== vdomNode._text
            if(textErr) {
                console.error(vdomNode, domnode)
                throw 'Text not the same'
            }
            return
        }
        const lenErr = vdomNode.content.length !== domnode.childNodes.length
        const typeErr = vdomNode.type.toLowerCase() !== domnode.tagName.toLowerCase()
        if(lenErr){
            console.error(vdomNode, domnode)
            throw 'Wrong number of children'
        }
        if(typeErr){
            console.error(vdomNode, domnode)
            throw 'Wrong type'
        }

        for(let i = 0 ; i < vdomNode.content.length; i++){
            checkSimlilarity(vdomNode.content[i], domnode.childNodes[i])
        }
    }

    checkSimlilarity(newVnode, document.querySelector('#app-root').firstChild)

    </script></body>

So the vdom-library thinks that the child of the first p-tag is an a-tag, but it actually is code-tag. Correct me if I'm wrong, but what I think happens is that the subsequent patch will then raise the exception.