Using Lumino with Vue
Lumino is the engine that powers the GUI of JupyterLab. It used to be called Phosphor JS, but some time ago there was a misunderstanding and the author gave up maintaining it. Then JupyterLab decided to fork it under this new name.
The documentation is still lacking, but it works as expected, and there is already a community supporting it. We decided to use it in Cylc UI to have tabbed panels like JupyterLab.
This project contains the part of the code of
Cylc UI that integrated Lumino and Vue. It was a suggestion from one of the maintainers
of JupyterLab, that got involved in an issue of Cylc UI. You can find this project linked
too in the Lumino project
Lumino handles the DOM directly, while Vue deals with a virtual DOM. So integrating both can be a bit tricky. And there are probably more than one way of doing it. So I am not claiming the route we went is the best.
The main component for this integration is called
Lumino. It has an array in its
data section that holds one entry for each widget that must be added to the Lumino
BoxPanel. The array can contain anything, like booleans or numbers. It holds the
ID of each widget added. This ID is the actual HTML element ID, and is used in the code
by even listeners to activate, delete, and maintain the state of the Lumino widgets and
the Vue components.
BoxPanel goes into a
div created in the component template, exclusively for
As Lumino stars working with the DOM before Vue has had time to move things from the virtual DOM, we need to compensate by asking Vue to wait before
The final step in the integration are wrappers for Vue components. These wrappers represent the component, but are actually used to attach the component’s HTML element to the widget HTML element.
.appendChild function in JS takes care of moving nodes within the DOM. And Vue
is smart enough to remove the element correctly. It should also take care of event
listeners automagically, but for safety I prefer to add and remove event listeners
Through even listeners, and controlling when something from the virtual DOM can access something from the DOM, and tricking Lumino into creating empty widgets that later receive the HTML element from the wrapped Vue component, we get it working with Vue in the same as Lumino works with JupyterLab.