Skip to content

Decouple Skeletor Views from Models

JC Brand edited this page Sep 9, 2020 · 1 revision

One useful feature of custom elements (i.e. web components without shadow dom), is that you can insert them into the DOM at any time, and they'll be dormant until the code that implements them executes.

There provides us with new possibilities.

For example, it allows us to have a declarative component tree for rendering, while still being able to disable certain view-layer plugins. The custom elements that those plugins would implement, then simply don't render.

It also provides the opportunity to decouple our existing Views from their Models, thereby helping us to transition to a more reactive and component-based architecture.

Currently, whenever a model is created, we generally will manually instantiate a view for that model, and the view will then manually be inserted into the DOM. The general goal is to replace all views with LitElement custom elements, however we can more quickly get to a componentized architecture by creating a Skeletor View that doubles as a custom element.

I've already done that here: https://github.com/conversejs/skeletor/blob/element-view/src/element.js#L24

Then we can start replacing the views in Converse with these custom element views. We create a new <converse-root> component which contains everything else, and instead of views being manually instantiated as they are now, it happens declaratively and as soon as they are inserted into the DOM.

The advantage here is that we can wait before we insert the <converse-root> (or any other custom element for that matter) into the DOM, while simultaneously already logging the user in to the XMPP server, fetching the roster, chats and messages and thereby setting up the state via the models and collections.

So we can set up the session and state, without needing to render anything yet, and then we only render as soon as we insert the <converse-root> element into the DOM.

This will make Converse work much more seamlessly with something like React, where a <Chat> component, which renders <converse-root> is only inserted into the DOM when a user wants to show the chat.

This approach could also make it possible to load the state for a MUC or chat in the background, without creating any hidden DOM nodes for it yet.