Prolog Virtual DOM
This is a Virtual DOM implementation for Prolog. It is designed to be used with the WebAssembly build of SWI-Prolog.
The implementation keeps the VDOM tree on the Prolog side and serializes the initial tree and modifications through the foreign language interface.
The Prolog code runs inside the WebAssembly module that contains running SWI-Prolog instance. The communication between the page and Prolog is done through the SWI-Prolog Foreign Language Interface (FLI) and the Emscripten API.
The application starts by rendering the initial state into the
initial VDOM tree, passes it to the page side and creates the
actual DOM tree based on it. The glue code in the browser
sets up generic event handlers (currently for events
submit). Event handlers are set on the body
element and rely on target element id's to differentiate between
VIn = div(, [hello]), VPrev = div(, [world]), vdom_diff(VIn, VPrev, Diff, VOut).
- VIn - current VDOM tree.
- VPrev - previous VDOM tree.
- Diff - serialized updates (
- VOut - current full VDOM tree.
In this example the first child of the root node is being replaced by the text node containing "hello".
VDOM nodes are either atomic terms or tags. Atomic terms are atoms, numbers and strings.
Tags have the general form of
name(Attributes, Body) and they
correspond to real DOM tags unless there is a component registered
with the same name.
VDOM components are both an abstraction and optimization tool.
Components are registered using the
predicate. Name refers to the component's name and Pred refers
to the component's rendering predicate.
Components with the same input data at the corresponding VDOM node are not re-rendered during the diff calculation. This allows to skip major parts of the VDOM tree in the algorithm.
Keyed node is a VDOM node where children have distinct
attributes. This is a common case where a list is rendered into
a list of VDOM nodes. The VDOM diff algorithm is able to:
- Reorder children effectively.
- Add/remove new children in/from the middle.
for a keyed node.
js/prolog.js- Prolog FLI bound using Emscripten.
js/patcher.js- Helper that applies patches onto the real DOM and forwards DOM events.
Construct a new Prolog FLI instance:
const prolog = new Prolog(module, args);
With the semi-official SWI-Prolog WebAssembly build,
[ 'swipl', '-x', 'wasm-preload/swipl.prc', '--nosignals' ]
Construct a new Patcher instance:
const patcher = new Patcher(prolog, root);
prolog is a Prolog instance and
root is the
application's root DOM element (it does not have to be
Atomic terms are serialized as strings.
where Value1 and Value2 are strings.
name(Attrs, body(Child1, Child2)).
where Attrs is an attribute term and Child1 and Child2 are serialized DOM subtrees.
DOM patch serialization
where Path is a path term and Dom is a serialized DOM tree as described in "DOM serialization".
where Path is a path term and Attrs an attributes term.
roc(Path, actions(Action1, Action2))
where Path is a path term and Action1 and Action2 are terms in the form:
Reuse term (reuses DOM node from the old index):
Create term (creates a new DOM node):
where Dom is a serialized DOM tree for the node as described in "DOM serialization".
Path term represents path from the root element down to
the element that is being modified. For example,
refers to 1st child of the root, and 3rd subchild of the child.
- Style updates.
The MIT license. See the LICENSE file.