Hi everybody,
i wonder what the mithril community is saying about the "new tech" that is currently coming up.
Me, personally, try to wrap my head around the
1: shadow dom/ web component
Because it seems it becomes natively available within the current major browsers and might take a lot of rendering performance done by nativ browser specs.
2: Memoized DOM
Here is a recent article: https://medium.freecodecamp.org/the-virtual-dom-is-slow-meet-the-memoized-dom-bb19f546cc52
Are there any other new approaches that are discussed within the mithril community? Is the current VDOM approach still "state of the art"?
I'm surely very satisfied with mithril and its overall approach, but i wonder if other approaches seem to be more future proof ...
Feedback appreciated!
Greets, Chris
Bye the way: I have made mithril hydration script that takes server side rendered dom (https://github.com/MithrilJS/mithril-node-render/) and hydrates it to be used for mithril. Thats mainly to avoid the FOUC when m.route / m.render initiates the app. Anyone interested? Its currently working buttery smooth on a bigger project.
Hi @ChrisGitIt ... There's certainly a lot of new exploration going on now that the vdom dust has settled. @isiahmeadows is also working on a new approach, so I'm sure he has a lot of interesting things to say.
My own preference is for mithrils hyperscript and lifecycle methods, so if it's a vdom or some other implementation below, I actually don't care much. I haven't bumped into any perf. issues I wasn't able to solve with mithril easily so I haven't been that drawn by other approaches that have popped up lately.
Your work on a hydration solution sounds very interesting, so if you'd be willing to share that I think a lot of people would be interested! Don't hesitate to come by the chat on gitter as well!
to do Memoized DOM in any meaningful way, you really have to pre-compile templates, which usually means writing templates that are no longer "just javascript", but a custom DSL*. the two paradigms are fundamentally incompatible. if you look at imba, it has its own template language. perhaps something like Vue or the original AngularJS could have mutated into something like this, but i dont think this can be shoehorned into any js-centric vdom framework.
i think there's room for implementing a detached dom node cache, given that you can solve one of the two most difficult problems in computer science: cache invalidation :) [1]
* i guess with sufficiently complex static analysis, like Closure Compiler level of complexity, perhaps it's possible to transform some part of a JavaScript AST into static templates you'd have to detect loop invariants, context/closures, string-key object accesses, etc. and give the compiler knowledge of vdom-style h functions.
/$0.02
Hi @porsager, and thanks for your feedback! I'm also very satisfied with the current mithril way and smile about other frameworks that are "opinionated" and mostly have a high learning curves.
About my hydration function:
You can see the mithril hydration in action on https://www.firstmallorca.com/en. Its mainly using a barely patched mithril version where
m.route(element, '/', routes);
got patched with a fourth argument like this
m.route(element, '/', routes, mithriHydrateFunction);
Within the mithril "render", there is only one line added that checks if there is currently a vdom created or not. The main problem i'm currently facing is when the rendered DOM is different than the mithril DOM. This only happens when the server side rendered dom is saved and served statically (also via CDN).
Wow.. That's a fast loading and good looking page @ChrisGitIt 馃憤
I'd love to try out your approach with bss in the mix which I'm also fixing up to support server side rendering currently..
Hi @porsager,
thanks for the compliments. The design is not my work. "Only" everything else ;-)
I just noticed that the js on the website is minfied. On test.firstmallorca.com you can see the unminified source code.
About using a JS-CSS approach: Currently working on a approach that works with SSR (server side rendering) AND that spills out the "above the fold" automatically.
I'm thinking about something where there is a special command that you place within your mithrils "main view" to accumulate the css until this point. Would look like this
function view(vnode) {
return m('main', [
m(component_nav),
m(component_header),
my-js-css.stopInlineCss(),
m(component_content),
m(component_footer)
])
}
Hi @ChrisGitIt , I'm definetely interested in your hydration script!
@ChrisGitIt
1: shadow dom/ web component
Because it seems it becomes natively available within the current major browsers and might take a lot of rendering performance done by nativ browser specs.
Fun fact: web components are slow, often slower than normal DOM elements. Native 鈮犅爁ast, and in this case, it's in part thanks to quite a bit of misplaced object-oriented indirection in the form of the shadow DOM itself. (Compare the performance of Vue and Ember with that of Polymer - they're all three similar to use, but they all three have very different performance curves, and Polymer isn't even close to the rest with list updates.) Custom elements and templates are still useful - custom elements make for some nice APIs, and HTML templates are way faster than document.createElement + elem.appendChild for building large DOM fragments.
Also, people suck at correctly managing mutation + asynchrony - most developers struggle how to correctly grasp it and rein it in, especially when using imperative languages. (Try writing a fast HTTP/2 implementation - it's harder than you'd think.)
Really, the main bottleneck here is list updates.
2: Memoized DOM
Here is a recent article: https://medium.freecodecamp.org/the-virtual-dom-is-slow-meet-the-memoized-dom-bb19f546cc52Are there any other new approaches that are discussed within the mithril community? Is the current VDOM approach still "state of the art"?
Virtual DOM is not the only approach anymore, and hasn't been for the last couple years:
There's been a bit of development in that area recently, so you can be forgiven for not catching on. Angular (starting with v4 IIRC) and Vue both use a traditional virtual DOM reconciler internally, so virtual DOM isn't going anywhere for a while, and this includes Mithril.
@isiahmeadows
One thing I thought of that could be very useful, is taking the incremental-dom approach (where you patch the DOM in-place after an initial render) but doing all the pre-work in simple document fragments
You could do a diff against A single document fragment (or many, doens't matter) before truly rendering out to the dom. This would give a couple of things (I been thinking about this alot since I got back from an extended leave)
This would still maintain the strengths (and largely leave the vdom implementation as is, with some optimizations)
asynchrounous patches and renders could be easily achieved, since you only push the fragment(s)
In theory, this could remove the need to have separate render/mount functions, since you could just target fragments on the page (and generate new fragments based on different mountpoints, which could make mounting against say, parent classes rather than element id selectors, easier?)
There is a speed benefit (no repaints is a nice win) this was taken from a stack overflow article
Since its a document fragment, you largely get the same APIs exposed as dealing directly with document, exception the subset of child elements is only the ones you care about (could be useful for building components on?)
One last thing I thought of, which may or may not be of interest: you could fire the life-cycle events as Custom Events too, this way, if that matters at all (I could see how this could, particularly as a consumer of the APIs. For instance: if I wanted something else happening on the page that may not be controlled/rendered by mithril directly, to fire an event that I want to trigger a lifecycle method, perhaps. While you could do this easily by just tieing it to an event attached to an element, this would make it easier, but might not be worth the headache?)
If I understand WebWorkers correctly, you could also do an RPC type thing with mithril where web workers yield fragments for rendering as well, this actually moves it off the main thread (note: I don't mean Service Workers though you could do something there potentially, I imagine. Just noting this for others)
I don't know if you have considered this. I would be very interested in putting together a demo if you want to explore this concept further. I don't know if I articulated this very well (i'm a little squeezed for time at the time of this writing ha!)
Maybe this idea has some legs for making improvements? I'm just happy to hear ideas!
I'm also happy to see mithril is seeing alot of new activity again, and I'm willing to help when/if able!
You could do a diff against A single document fragment (or many, doens't matter) before truly rendering out to the dom.
document fragments are emptied once they're inserted into the live dom, so there's nothing left in them to diff against.
You could do a diff against A single document fragment (or many, doens't matter) before truly rendering out to the dom.
document fragments are emptied once they're inserted into the live dom, so there's nothing left in them to diff against.
Oh fair enough (having not investigated it closely as I thought, didn't now that). Is it possible that it might be worthwhile to explore window.localStorage to cheaply save and compare? or am I just getting out of the realm of what we might want to do with that?
Though, I think rendering against a docfragment and keeping the state elsewhere would serve still be a worthwhile endeavor considering the other factors.
@ProtonScott If you read the source, we already use fragments for quite a few things, including rendering Mithril fragments.
@isiahmeadows I see, maybe the aptly named $doc threw me off in my search (or maybe its been too long since I looked at the source code).
So what do you think the way to spearhead is the way to go to improve rendering/performance?
@ProtonScott To address the other points:
@isiahmeadows
One thing I thought of that could be very useful, is taking the incremental-dom approach (where you patch the DOM in-place after an initial render) but doing all the pre-work in simple document fragments
You could do a diff against A single document fragment (or many, doens't matter) before truly rendering out to the dom. This would give a couple of things (I been thinking about this alot since I got back from an extended leave)
We already do this a lot.
removeChild, though.This would still maintain the strengths (and largely leave the vdom implementation as is, with some optimizations)
- asynchrounous patches and renders could be easily achieved, since you only push the fragment(s)
We're missing browser APIs for that. That's the real bottleneck in the DOM currently. Browsers already currently render off-thread as much as possible, so async paints aren't an issue. It's been discussed before, since we aren't the only ones who need it (it's something most frameworks could use):
Sadly, nothing meaningful has arisen out of it yet.
- In theory, this could remove the need to have separate render/mount functions, since you could just target fragments on the page (and generate new fragments based on different mountpoints, which could make mounting against say, parent classes rather than element id selectors, easier?)
m.render just does a single render + update. m.mount lets you subscribe to updates, update the last tree, and automatically redraw based on various events.
- There is a speed benefit (no repaints is a nice win) this was taken from a stack overflow article
- Since its a document fragment, you largely get the same APIs exposed as dealing directly with document, exception the subset of child elements is only the ones you care about (could be useful for building components on?)
- One last thing I thought of, which may or may not be of interest: you could fire the life-cycle events as Custom Events too, this way, if that matters at all (I could see how this could, particularly as a consumer of the APIs. For instance: if I wanted something else happening on the page that may not be controlled/rendered by mithril directly, to fire an event that I want to trigger a lifecycle method, perhaps. While you could do this easily by just tieing it to an event attached to an element, this would make it easier, but might not be worth the headache?)
Custom events would be slower. Currently, hooks are literally just simple function calls, and custom events would require a lot more ceremony to fire and listen to.
- If I understand WebWorkers correctly, you could also do an RPC type thing with mithril where web workers yield fragments for rendering as well, this actually moves it off the main thread (note: I don't mean Service Workers though you could do something there potentially, I imagine. Just noting this for others)
Just trust me in that it's easier said than done. 馃槈 It'd also take a lot of code.
I don't know if you have considered this. I would be very interested in putting together a demo if you want to explore this concept further. I don't know if I articulated this very well (i'm a little squeezed for time at the time of this writing ha!)
Maybe this idea has some legs for making improvements? I'm just happy to hear ideas!
I'm also happy to see mithril is seeing alot of new activity again, and I'm willing to help when/if able!
@ProtonScott To address the other points:
@isiahmeadows
One thing I thought of that could be very useful, is taking the incremental-dom approach (where you patch the DOM in-place after an initial render) but doing all the pre-work in simple document fragments
You could do a diff against A single document fragment (or many, doens't matter) before truly rendering out to the dom. This would give a couple of things (I been thinking about this alot since I got back from an extended leave)We already do this a lot.
- Every fragment appended
- Every time this function is called, and it's called in 4 spots (1, 2, 3, 4. The last one isn't ussing the result and could be optimized to just use
removeChild, though.This would still maintain the strengths (and largely leave the vdom implementation as is, with some optimizations)
- asynchrounous patches and renders could be easily achieved, since you only push the fragment(s)
We're missing browser APIs for that. That's the real bottleneck in the DOM currently. Browsers already currently render off-thread as much as possible, so async paints aren't an issue. It's been discussed before, since we aren't the only ones who need it (it's something most frameworks could use):
Sadly, nothing meaningful has arisen out of it yet.
- In theory, this could remove the need to have separate render/mount functions, since you could just target fragments on the page (and generate new fragments based on different mountpoints, which could make mounting against say, parent classes rather than element id selectors, easier?)
m.renderjust does a single render + update.m.mountlets you subscribe to updates, update the last tree, and automatically redraw based on various events.
- There is a speed benefit (no repaints is a nice win) this was taken from a stack overflow article
- Since its a document fragment, you largely get the same APIs exposed as dealing directly with document, exception the subset of child elements is only the ones you care about (could be useful for building components on?)
- One last thing I thought of, which may or may not be of interest: you could fire the life-cycle events as Custom Events too, this way, if that matters at all (I could see how this could, particularly as a consumer of the APIs. For instance: if I wanted something else happening on the page that may not be controlled/rendered by mithril directly, to fire an event that I want to trigger a lifecycle method, perhaps. While you could do this easily by just tieing it to an event attached to an element, this would make it easier, but might not be worth the headache?)
Custom events would be slower. Currently, hooks are literally just simple function calls, and custom events would require a lot more ceremony to fire and listen to.
- If I understand WebWorkers correctly, you could also do an RPC type thing with mithril where web workers yield fragments for rendering as well, this actually moves it off the main thread (note: I don't mean Service Workers though you could do something there potentially, I imagine. Just noting this for others)
Just trust me in that it's easier said than done. 馃槈 It'd also take a _lot_ of code.
I don't know if you have considered this. I would be very interested in putting together a demo if you want to explore this concept further. I don't know if I articulated this very well (i'm a little squeezed for time at the time of this writing ha!)
Maybe this idea has some legs for making improvements? I'm just happy to hear ideas!
I'm also happy to see mithril is seeing alot of new activity again, and I'm willing to help when/if able!
@isiahmeadows Welp, turns out I'm a complete noob at this, aren't I ? 馃檨 馃槅
I appreciate the detailed response, very much so. I will just put the hat in the bag for now.
Closing this in favor of #1838.
Most helpful comment
@isiahmeadows Welp, turns out I'm a complete noob at this, aren't I ? 馃檨 馃槅
I appreciate the detailed response, very much so. I will just put the hat in the bag for now.