PhoenixUndeadView - let's discuss optimization possibilities for something like Phoenix LiveView

From what I’ve found, it seems like the bottleneckin morphdom is parsing HTML strings. But morphdom has a spec for compatible VDOMs. Maybe if I send JSON encoding a VDOM (which will require some processing by client-side Javascript) and it will be fast? I have to ask it in a morphdom forum.

With a proper vdom patch or observables it just wouldn’t happen, at all, unless the value was explicitly changed from the server, if it’s an untouched value then it just wouldn’t be touched, so no updating would happen and thus it wouldn’t get cleared.

Not handy (useful I know), been busy at work and the computers are lagging crazy… >.>

Yep, as mentioned above it is the build-up and the tear-down of the DOM tree it builds from a string that is slow, the DOM<->DOM (or a compatible vdom on one) is much faster, normal vdom style speed, which is still slower than direct access, but would be significantly more worth it, however you are just moving the cost from the patching to the build of the vdom structure on the client (which is still much faster than instancing actual DOM elements to test with).

This forces me to have actual diff algorithms instead of just rendering everything and sending it to the client so that it can sort it out… This is something I’ve been trying to avoid. The whole point of Vampyre is that it wastes no time in diffing stuff. It just renders everything and sends it down the pipe.

1 Like

The diff would only be on the client, the server would just send the changes to the dynamic content changing. :slight_smile:

And how does the server know what has changed without diffing the VDOM? By building a dependency graph and diffing the data? Or by requiring Drab-style poke updates that only work on the top level? For that we already have Drab…

I guess I’d rather implement (optimized) VDOM diffing on the server than any of the other options.

I’m actually working on some jsx like parser for elixir: https://github.com/olafura/eex I’m extracting it from https://github.com/olafura/scenic_jsx I also have a json diff library that might be useful https://github.com/olafura/json_diff_ex

1 Like

I had forgotten about this. It seems useful. Maybe I could use it to diff the DOM directly, but I’m still undecided on whether I want to go the virtual DOM route… As I said above, it’s a big departure from what I’m doing now (and most likely much slower on the server, even if it might be faster on the client).

This is not a change I can make in a backwards-compatible way, so it’s not something to take lightly. And if I go the current route (which allows semantically wrong HTML), I can’t easily convert it into something more “typesafe”.

But if I start with something typesafe, then I’l need to implement some restrictions on the templates. Depending on how “dynamic” I want the templates to be, it might comicate the implementation somehow, but it should be possible.

The problem is that it will be radically incompatible with Phoenix.HTML. If you’re generating semantically correct HTML there is no place for Phoenix.HTML.Tag.tag, which returns an unclosed HTML open tag! In my opinion this was a very bad design decision, but it’s not something I can change in the Phoenix.HTML project… So I’m really undecided about this.

Not that user use the Tag widget that much, mind you. I think people mostly use widgets implemented on top of Tag, like text_input, form_for, etc.

The server doesn’t know nor should it know the structure of the DOM at that point, it only sends data updates and the client performs its own changes. No point doing that on the server when the client can do it better. Even then the client would not diff anything, it would only receive the new data payload and then adjust the dom directly.

Doesn’t that require cross-compiling the Elixir template into Javascript?

No? The elixir side just sends data that changes to the client, the client javascript just takes that data along with the page-embedded dataname<-id’s mappings to determine what to update and how. It will involve some javascript writing but it’s not a ton by any stretch.

By “sending data” you mean a representation of the DOM which isn’t actually HTML then?

Nope, no DOM representation at all, literally the data, think of the assigns in the template, if any part of it changes then you just do one of two things (depending on library design), like serialize it out to something the javascript side can handle, so if something like @title (assign[:title]) changes then you just send a json patch of like {"title":"newtitle"} (and the json patch formats for updating parts of a string or arrays or so is quite good), or you can generate a set of commands to modify based on pre-baked information at compile time of the data to ID mappings and send those json commands across (a refined/enhanced version of Drab’s style).

You’re basically describing cross compilation of a template to javascript.

Eh, kind of for the first method, except where it just encodes what it needs to know to rebuild the parts that each data access, and not at all for the second method.

Refining drab seems hard… I think Drab is already operating near the limit that its mode allows. It could be improved by merging it with morphdom (send the parts of the dom you need to update as literal html and let morphdom diff them), but IDK.

Oh not at all, there are many opportunities for efficiency enhancements! A lot of what I said above for example.

Oh that would be much worse! Right now say you have something like <span class="blah">Value: <% @stuff %></span> in a deep DOM tree and the @stuff value changes via a commander, right now it sends a tiny little bit of javascript that directly edits the span’s text element. Compare that to if using morphdom where you’d have to send the entire DOM tree over down to whatever marked point as a string and let it iterate over the entire thing to find the specific difference to update just that one point, which is both incredible worse in both speed and network bandwidth both!

No you don’t. You can simply tell morphdom to replace the contents of that specific span tag. In this case there is no advantage compared to ussing span.innerHTML = ..., but in other cases there might be an advantage. Morphdom can patch any element of the DOM, it doesn’t have to patch from the root.

I’m not making use of that in Vampyre, of course. With Vampyre, I’d have to ask morphdom to generate the whole DOM from the root and then diff it. Which, as you say, is very inefficient. But my main target was to send as little data through the network as possible, and I think I’ve succeeded with that. Maybe it was not the best target, though.

But if you already have the direct element then why not set it directly then so you don’t incur the cost of parsing the string, performing the diff, etc… when you can just set the new value immediately?

Uh, wouldn’t this send just about the ‘most’ amount of data through the network as possible though? o.O

No, because I cache the static html fragments on the client and only send the dynamic fragments from the server. That’s the while point of yhe UndeadView project! Vampyre is just a spinoff which doesn’t implement the transport layer (which hasn’t been written yet) and which (as a side effect of optimizing for data transmission) is very fast

You can see how it’s supposed to work by re-reading the first post in this thread :slightly_smiling_face: