-
Notifications
You must be signed in to change notification settings - Fork 97
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
Research about replacing Knockout.js by a virtual DOM with maintaining full back compat #383
Comments
I really like this idea. I can imagine a Knockout JS compatible wrapper over the viewmodel which would provide the subscribes and value update callbacks. I can also imagine preserving the compatibility of the controls with excluding a particular elements from the VDOM diffs - a control could say "hey, this is my element, I am going to manage its contents by myself, so don't diff inside, just call update in the binding handler when something changes". But let's face it - this is a very big thing and I don't think we should start with this until DotVVM has significantly more users than now. |
I didn't think that copying the properties would be a problem, but may be a problem for correctness when a property would be added to the object. But ES2015 has a Proxy object for that. Unfortunately, it's not supported by IE, so we will probably have to copy the properties https://caniuse.com/#feat=proxy The virtual-dom library supports thunks - objects that handle the diff by itself, so it would be possible, but I don't think it'd be necessary, the V-DOM will not update if it hasn't changed, and if it did, it would re-register the binding handler. |
I agree that this is probably the biggest refactoring we did in DotVVM and it certainly would not be that straightforward as I have just described, but when we will have more users, there will be more stuff to break and more time spent in hacking knockout flaws. |
I think it will be necessary to exclude some elements from diff, but only for compatibility reasons. Complex UI controls may have some state that would be reset by re-registering the binding handler. That's not always what you want. We can't store everything in viewmodel. We will need better concept of UI controls. Controls will always have internal state that will not be stored in viewmodel and there must be a way to update VDOM when state is changed. It's actually very similar to how React components are updated. Also we need to handle communication between two controls. Rendering is the tricky part. We need to render everything on server and make updates on client. But we should keep the rendering logic in one place. But how? With enriched HTML we will probably never get rid of If we wait for DotVVM to have significantly more users, it will be significantly more difficult to make this real. |
@djanosik These are all good points, thank you.
I'm not exactly sure what do you mean by control communication, but the ViewModel should be the best place where to exchange information, why is it unusable for the controls? Maybe it would be better to make the viewModel more usable for control state than hiding the state somewhere. |
|
|
|
|
Hello,
|
@darilek I don't know Aurelia at all, so it may be very helpful you would share some experiences. Do you have tips for concrete parts, that I should have a look at? However, I don't like the concepts very much as the two-way binding is actually the thing that I'd like to get rid of and nicely usable components are not a killer feature for a generated code. I'm convinced that immutable VDOM is much cleaner architecture at a cost of being less comfortable for direct usage, which does not matter for a generated code. The mentioned virtual-dom library has very simple yet quite powerful API, in contrast with Aurelia's complex templates (at least seems to be complex from a quick glance, and it actually makes sense for "end-developer" framework, DotVVM also has very complex control infrastructure and React with all the libraries to make it useful would not be much simpler) |
Really was thinking to use DotVVM as main framework but this issue is making me skeptical. I have just added it to my asp.net core app and was impressed how it integrate seamlessly. |
Don't be afraid. There are several things to keep in mind:
- This is a very distant future. Currently, we work on version 1.2 which will bring a lot of new features - REST API bindings, postback concurrency modes etc. VDOM is not coming sooner than in a year.
- We are still considering whether this is a good idea or not and how to approach it. Knockout has a lot of limitations which will cause more and more problems in future. Right now, we can live with it quite well.
- If we decide to do this change, nothing will change from the user perspective. The syntax, the controls, everything will remain the same. We will have to keep most of the Knockout public APIs to preserve the compatibility. We have been able to add .NET Core support with only minimum breaking changes and it will be the same with the VDOM. We already have a lot of controls and apps which we definitely don't want to rewrite.
I agree that we should compose a proper roadmap, but really, there is nothing to worry about. We wouldn't do such a big change if we wasn't really convinced that we can maintain the backwards compatibility.
Should you have any other thoughts or concerns, feel free to contact me, we can talk privately if you prefer. I will be happy to talk about this.
S pozdravem
Tomáš Herceg
RIGANTI s.r.o. | DOTNETCOLLEGE s.r.o. | DotVVM
www.riganti.cz<http://www.riganti.cz> | www.dotnetcollege.cz<http://www.dotnetcollege.cz> | www.dotvvm.com<http://www.dotvvm.com>
…________________________________
From: zulq <[email protected]>
Sent: Wednesday, July 19, 2017 5:42:30 PM
To: riganti/dotvvm
Cc: Subscribed
Subject: Re: [riganti/dotvvm] Replace Knockout.js by a virtual DOM (#383)
Really was thinking to use DotVVM as main framework but this issue is making me skeptical. I have just added it to my asp.net core app and was impressed how it integrate seamlessly.
I believe not to scare away potential users, you should put a proper roadmap and any other ways of restoring potential/existing users confidence. Just my two cents.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub<#383 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/AM7fr-uBQoXqLQVnkXN4dJZph4xl9aqiks5sPiPmgaJpZM4OZACS>.
|
@zulq Actually the backward compatibility is the main concern of this issue, so you can be quite sure, that everything will work (in the compatibility mode) even after this change unless you'd use some We don't want to take the Angular's or Python's way of breaking the most used APIs :) |
Thanks @tomasherceg and @exyi for the feedback. Will continue exploring. |
@zulq DotVVM started before ASP.NET Core and Tag Helpers were announced. That's why we have our own view engine, parser and things like that. Months ago, we was talking about making some integration between Razor and DotVVM, so you could host a DotVVM user control in a Razor view or vice versa, or to be able to share "master pages", but I don't know if that's really useful. |
@tomasherceg I think it will be useful especially sharing master pages. I believe it will also encourage people to use DotVVM knowing that one can mix and match both. |
@zulq Yes, but there are very few master pages in every project, so the advantage of sharing them is not so significant. |
Agreed. |
Just an idea: it could be cool to write user control in Fable using the virtual dom in a similar way fable-arch works and render it client-side and server-side using the same piece of F# code. |
Have you looked at Vuejs? Comparison with Knockout https://vuejs.org/v2/guide/comparison.html#Knockout |
@zulq We know it. The problem is that basically, Vue is Knockout with all its goodnesses and flaws. They mention it on the page - "the Vue's reactivity system is very similar". |
* Created a knockout compatibility layer, so that TaskList and simple GridView samples can run unchanged. This includes knockout virtual elements and binding handlers that manipulate the datacontext of their content * There is actually no way to use the v-dom functionality, the only interface is through the knockout compat layer see #383 for some context
Ok, I suppose that backward compatibility can be fun, at least sometimes - this was a quite cool weekend project ;) I managed to create a proof-of-concept implementation of the knockout compatible virtual-dom based dotvvm. Current status is that the task list and some GridView samples seem to work, basic features like (two way) data binding and postbacks are probably ok, but more advanced features like On page init it builds an AST from the DOM that was transferred from the server, that is then used as a render function. Each element is checked if it does contain anything If you have any questions, you can probably find the answers in the code, it's in |
Implementation Status UpdateI have moved the implementation quite significantly in past few days. It seems to me that majority of the samples should now work (completely on the compatibility api!), but I have not run the UI tests ValidationIt's migrated to the new architecture - the validation errors are stored in the immutable state object next to the validated property in a field called Postback.Update and SPAsAll controls that have |
I have looked at some virtual-dom implementation which would be usable in dotvvm. The proof-of-concept is implemented using https://github.com/Matt-Esch/virtual-dom, which is simple, works and I don't have any problems with it. Anyway, there is a ton of alternatives, so it may be worth considering them.
|
I think that we should use React or Preact. All major companies that develop controls support React right now. And being a framework based on React, we'll look cool! |
I really like the Preact library. Do you want to use its server-side rendering? Is it ok for DotVVM to require Node.js? |
I am not sure how this would actually work. |
Yes, I'd really like to support server-side rendering of Preact controls, although I don't think we should use that in DotVVM itself to avoid the node.js dependency. It may be ok to use that in Bussiness pack, but there is not much benefit of using it in the core of dotvvm, the controls are usually quite simple and I don't want to spend performance on the .NET/Node communication.
A (P)react control is basically a function that gets viewModel and returns a virtual dom, so you invoke the function on the server and serialize the virtual dom to html. |
FYI: I have arraged a weekend planaton for this saturday/sunday with @tomasherceg about dotvvm 3.0, mainly about new control rendering system. If you'd be interested to participate (physically, a call about certain idea, whatever), drop me an email. We will certainly publish the results. |
I'm just learning about DotVVM, and it looks quite interesting. This thread piqued my interest as well because I've been looking into client side JS frameworks. If you're looking for something React-compatible, then Inferno is the way to go. It's by far the fastest and leanest React-compatible library. If you just want a simple virtual DOM library, then something like PicoDOM or Ivi are very lightweight and the best performers. If you want the best performer overall, then you're looking at Surplus based on S.js. It doesn't actually use a virtual DOM, it manipulates the DOM directly using reactive expressions, which is why it's typically the fastest in benchmarks. That's my two cents! |
@naasking Thank you for the recomendation, but I still like using Preact the most, so I'd like to briefly explain why. Using something React-like is a great advantage as most React controls would just work with DotVVM (without any compromises). And it does not actually matter that much which one will we choose, as swaping them should be easy. I like the Preact, because it's really lightweight and pretty simple, but you could certainly switch to Inferno or React in your application or we could change the default later, if Preact would be causing some problems.
Note that we are also looking at integration with Blazor, which looks pretty promising. Although I'm not really sure what will come from that, it could also substitute the VDOM migration. |
Certainly choose which better matches your model, but I wouldn't hesitate to recommend Surplus based on S.js, as it's superbly engineered. It takes pretty much every top spot for performance and memory use in the comprehensive JS framework benchmark suite. Peruse the filterable results table here. Knockout.js is in that suite as well, and it falls well below the others with an average overhead of ~2.14x over vanilla js, where Inferno is ~1.14x, Preact ~1.31x, and Surplus is ~1.05x. Definitely worth considering at least! |
We plan to replace the Knockout.js library by an immutable viewmodel with virtual DOM - something similar to React.
Motivation
Although knockout.js is IMO well implemented and stable library, the UI updating architecture is a bit glitchy - for example, the
<select>
binding made us a whole bunch of problems because it's bound to multiple properties that are not changed atomically and the combination of properties between the changes is invalid, so the control breaks. And even though we came up with few hacks to fix the concrete problems, we can IMHO expect similar issues with other controls.The second problem is client side performance with larger than the small data set. I have no idea how to make it better with knockout and sometimes it is a real problem. And again, the problem lies in the observable notifications.
Another problem is rendering a template without wrapper tag - although knockout has a concept of virtual elements, the performance is really bad (~6x), not all bindings are supported and HTML comments are sometimes stripped off by compression proxies.
How would it work with DotVVM
I propose migration to virtual DOM architecture. https://github.com/Matt-Esch/virtual-dom library looks lightweight and extensible enough, so let's talk about it, but all the V-DOM implementations are quite similar, so we can choose the better one later.
ViewModel
The viewmodel would be a simple JS object without the observables that will never mutate (maybe we could use a immutable object library but I think it's unnecessary). Because the properties can't be mutated, there is no need to observe the property changes and the viewmodel must be replaced by a completely new one. On the first glance this may look like a crazy performance hit, but as you can reuse parts from the old one, it only does
O(number of changes)
allocations, and has completely superior performance in comparison with the change notifications. It would also enable us to track old states for debugging purposes and has IMO much simpler to understand architecture.Rendering
Now DotVVM controls render HTML enriched by the knockout
data-bind
attributes, which is intuitive to read and understand. The knockout binding handlers are tightly integrated with the DOM and are created based on thedata-bind
attributes on page init. React and other V-DOM frameworks on the other hand use Javascript functions instead of enriched html to create the virtual DOM and update the real one, which is quite incompatible with the DotVVM control architecture. I think the best solution would be to generate enriched html by adata-render
attribute and generate the render function from that. But there is a bunch of other possible options like rendering plain html with the render function on the server.Compatibility
Now, you probably think that all this is nice, but this is going to break everything or how the hell do you want to maintain backward compatibility. Of course this change is going to break a lot of things, but I'd like to maintain compatibility for basic usage of the Javascript API and for simple controls. I'd reimplement part of the knockout API for the immutable viewmodel and export
ko
global.dotvvm.viewModels.root.MyProperty().Prop123()
andko.contextFor
- we can return something that will look like a ko.observable and the subscriber will be notified when the entire viewModel is changed.The text was updated successfully, but these errors were encountered: