Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next Steps #195

Open
leeoniya opened this issue Dec 22, 2017 · 6 comments
Open

Next Steps #195

leeoniya opened this issue Dec 22, 2017 · 6 comments

Comments

@leeoniya
Copy link
Member

leeoniya commented Dec 22, 2017

the current dom insertion/removal/reordering reconciler [1] relies on 1:1 vnode-to-element mapping. this design prevents proper implementation of fragment vnodes, which in turn forces all views to return a single defineElement() vnode.

to resolve this impasse the reconciler must be:

  1. modified to use the old vtree rather than the dom. this is fairly straightforward.
  2. augmented for handling fragment vnodes. this is a bit more involved but workable.
  3. optimized to do parent-down rather than children-up reordering. this can significantly reduce the DOM load by not doing meaningless DOM ops. for instance, in React's fragment impl, a 12 fragment reversal (with in-fragment reversal) results in 34 appendChild calls [2]. the ideal count should be 23 appendChild (or insertBefore) calls. this appears to translate to ideal fragment revrsal (11) followed by in-fragment reordering (23). the issue in domvm's case is that it has will/didReinsert lifecycle hooks, so rather than calling 1 per move, it would call multiple (one for each useless move). i think this nicely illustrates the perf overhead that can grow exponentially in dealing with fragments.

[1] https://github.com/leeoniya/domvm/blob/3.x-dev/src/view/syncChildren.js
[2] https://codepen.io/anon/pen/zpdRKQ?editors=1000

@lawrence-dol
Copy link
Collaborator

I am not sure I understand the problem very well, but could the hooks be invoked for logical "net result" operations. So if the net result was to take [1,2,3,4] and end up with [4,1,2,3] that would be one remove for 4 and one reinsert for 4, not (logically) passing through [1,2,4,3] and [1,4,2,3] on the way.

@leeoniya
Copy link
Member Author

leeoniya commented Apr 20, 2018

the current reconciler will do the correct/optimal thing in pretty much all cases. in your example it will only do willReinsert(4)/didReinsert(4) in both actual dom ops and hooks (which are fired by dom ops).

one problem this issue addresses is when you have hooks on fragments or other vtree components like immediately nested views or views returning null from render that will not or cannot exist in the dom. since the current reconciler walks the real old dom, it never encounters vnodes that dont have a physical dom presence.

this is why you currently cant have views that directly return other views, fragments or have render functions that return null while still retaining the stateful/declarative component in the vtree despite removal from dom. if we walk the old vtree in the reconciler, then a lot of this stuff becomes possible and delivers on some additional benefits of maintaining a vdom rather than being partly or purely dom-based #196 ;)

@lawrence-dol
Copy link
Collaborator

It seems like (1) reconciling against the old vDOM is sensible to do regardless and would make DOMVM immune to in-hook DOM manipulation.

I wonder if fragments might be doable then by using a special psuedo-tag, say, "domvm-fragment", which when processed by the hydrator would simply be ignored, inserting the children instead?

function fragment() {
    return elm("domvm-fragment", {...}, [
         elm("tr", ...),
         elm("tr", ...),
         elm("tr", ...),
         ...
         ]);
    }

Just an idea to chew on.

@lawrence-dol
Copy link
Collaborator

@leeoniya : I suggest enabling discussions and moving this to a discussion.

@lawrence-dol
Copy link
Collaborator

Now that we have CSS display: contents, is it still necessary to support fragments? One can wrap the fragment in a <div style="display:contents"> and get 95% of the way there. I've done this successfully in a few places.

I think the only gotcha is that CSS immediate child selectors are sensitive to the intervening node so div.table > div.row won't select the following row:

<div class="table">
    <div class="row-group" style="display:contents">
        <div class="row">
...

@lawrence-dol
Copy link
Collaborator

@leeoniya : Should we close this as unneeded due to support for display contents and subgrid (landing this year)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants