Tiberiu Ichim: Volto Pluggables

published Nov 08, 2021

Talk by Tiberiu Ichim at the online Plone Conference 2021.

This presentation is an introduction to the new Volto developer-targeted feature, the Pluggables framework. It is more an argument for extensibility in CMS UI and in Volto.

Basically, with Pluggable a central component provides a pluggable slot that other components can fill, like this:

<div className="toolbar">
<Pluggable name="toolbar-main" />
</div>
// ...
<Plug id="quicklinks" pluggable="toobar-main">
<Button />
</Plug>

This is a Volto port of https://github.com/robik/react-view-slot.

The big picture:

  • I work with Eaudeweb Romania
  • Our client EEA is an early adopter of Volto
  • The strategy is: move everything to Volto
  • But the EEA sites are less brochure, the CMS side is really strong.
  • We build powerful UIs for power users.
  • The EEA already has 91 Volto repositories on GitHub. How can we scale that? Can we write an add-on to make it easier to write an add-on?

In React, data flow is top to bottom. A parent component passes properties to children and children communicate with the parent by emitting events. This makes sense and works well. For "out of tree" data you need Redux. There is no protocol for add-hoc communication between components.

UI state is fluid. Extensibility means reusability and scalability. This is hard. You need to design upfront. Plone backend uses the Zope Component Architecture, which means pluggability is baked in, it is very natural. You can view Pluggables as viewlets-on-demand, but they are really not. But yes, you can think about a Pluggable as a viewletmanager and a Plug as a viewlet.

You can overwrite a Plug with a Plug, by registering it with the same id. So if the original Plug gives you color blue, you can overwrite it with color red.
You can do custom rendering of Plugs within your Pluggable, by iterating over all Plugs and for example wrapping each in a div with a class name.

Showcase: volto-workflow-progress (main toolbar plugin) and volto-editing-progress ("sidebar" for plugin).

Limitations:

  • No Server Side Rendering
  • Watch out for dependency lists.
  • Limited adoption for now.

Implementation in pseudocode:

First the context:

<PluggablesProvider>
<Pluggable name="top" />
<Plug name="delete" />
</PluggablesProvider>

Then the dumb version of the Plug:

const Plug = ({id, children}) => {
const { register } = useContext(PluggablesProvider.Context);

React.useEffect(() => {
register(id, () => children);
});

return null;
}

Takes a bit of study, but in the end it is not so hard.
The Pluggable becomes a bit simpler:

const Pluggable = (name) => {
const { getPlugs } => useContext(PluggablesProvider.Context);
return getPlugs(name).map(f => f());
}