defineFragment
See original GitHub issueAfter a third and final attempt at defineFragment
, I landed something that’s robust enough to work, has 0 perf overhead for non-fragment nodes, and has no needed DOM placeholders. So far there’s support for adjacent fragments, nested fragments, fragments returned from render(), views wthin fragments [1].
There are some caveats. Fragment nodes are not 100% like normal vnodes. They do exist in the vtree, but are flattened and transparent to the dom reconciliation algo. This means that they will not themselves support some lifecycle _hooks (at least initially) or any event handlers (cause they have no dom to bubble through), etc… However they can hold _key
, _data
, _ref
and other vtree-only stuff, if you need to reference some model/key from any hooks or handlers bound to any contained elements.
So far, the implementation adds about 0.6k (min) [2] to every build since support has to be integrated into various parts of the core. There’s still some work left to get them fully useful, which will add perhaps another 0.1k-0.3k:
sig:DONEdefineFragment([ type [, attrs], ] body)
, right now it’s onlydefineFragment(body)
explicit vm.redraw() of sub-views with fragment rootsDONE- ensure vnode.patch() works (may not be applicable)
- look into adding hooks based on vtree grafting pass rather than dom reconciliation pass
- refine dom reconciliation boundaries and fragment flattening (forward only) when doing fragment root redraw
- html() support
- tests
fragment root in top-level view (maybe)PROBABLY NOT
[1] https://github.com/leeoniya/domvm/blob/defineFragment/demos/fragments.html
Issue Analytics
- State:
- Created 7 years ago
- Reactions:1
- Comments:9 (5 by maintainers)
Top GitHub Comments
Fragments will have worse performance characteristics than flattened templates. In benchmarks (and extreme stress cases) it would be significantly worse but in real life apps you’re unlikely to notice the difference.
The reason is that all Element vnodes that contain a fragment child must create an additional flattened body representation & all Element descendants must be tagged with the actual Element parent before hitting the dom reconciler which runs a simple iterator over the body array. This is both unavoidable and must happen on every redraw, but again, in typical apps you probably won’t be able to measure a difference unless you do something careless like call
vm.redraw()
on unthrottledmousemove
,resize
, orscroll
events or render 10k-row tables.Consider fragments to be a template authoring and state-wrapping convenience. They are unlikely to improve redraw performance and will not be promoted as such.
returning fragments as view roots would probably be the main use case here.
the main benefit is wrapping state and redraw isolation around some adjacent subset of dom nodes. for instance, many DOM elements cannot have arbitrary nesting levels. eg. you can’t wrap a
<div>
around some adjacent set oftd
s to get isolated redraw.another use is defining the body as a sub-view (with a fragment root) and the wrapper in the parent. this is quite useful to prevent wrapper duplication (or having to externalize the wrapper in a function) across multiple similar views.
yet another use if to avoid having to do
vnode.patch()
to set only the wrapper’sdisplay:none
and prevent further redraws of body viavm.diff
.you can also use fragments to store some arbitrary data/state on the fragment vnode that pertains to its children rather than copying that data to every child.
at the end of the day it’s a nice-to-have feature that isnt exactly necessary, but can make some convenient constructions less grotesque. unfortunately, fragments cannot be implemented as an addon because the core reconciler must know how to handle them. so they add a size weight to all builds, but hopefully no perf overhead when unused (if i implement them carefully).
what’s available now (array flattening that has no representation in the vdom) is a convenience feature for declarative templates, but if you use imperative template construction (as you’re showing), they don’t add much value anyways cause you can just use concat()/push() to build up the body.