Mounting is the initial render when your application or component first appears. The mountDOM() function from packages/runtime/src/mount-dom.js creates real DOM nodes from your virtual DOM tree.
From packages/runtime/src/mount-dom.js:25-49, GlyphUI handles four types of nodes:
Text Nodes
Text nodes are created using document.createTextNode():
function createTextNode(vdom, parentEl, index) { const { value } = vdom; const textNode = document.createTextNode(value); vdom.el = textNode; // Store reference to real DOM node insert(textNode, parentEl, index);}
The real DOM node is stored in vdom.el for future updates.
Element Nodes
Element nodes create HTML elements with attributes and children:
function createElementNode(vdom, parentEl, index) { const { tag, props, children } = vdom; const element = document.createElement(tag); addProps(element, props, vdom); // Add attributes and event listeners vdom.el = element; children.forEach((child) => mountDOM(child, element)); insert(element, parentEl, index);}
Children are recursively mounted before the parent is inserted.
Fragment Nodes
Fragments render their children directly without a wrapper element:
function createFragmentNodes(vdom, parentEl, index) { const { children } = vdom; vdom.el = parentEl; // Reference parent since fragment has no element children.forEach((child, i) => mountDOM(child, parentEl, index ? index + i : null) );}
Fragments don’t create a DOM element. The vdom.el property references the parent element instead.
Component Nodes
Components are processed by instantiating the component class and mounting it:
Patching is the core reconciliation algorithm that efficiently updates the DOM when state changes. Instead of recreating everything, GlyphUI intelligently determines what actually changed.
From packages/runtime/src/patch-dom.js:19-118, the patching process follows these steps:
export function patchDOM(oldVdom, newVdom, parentEl, index) { // 1. Mount if there's no old vdom if (!oldVdom) { mountDOM(newVdom, parentEl, index); return newVdom; } // 2. Destroy if there's no new vdom if (!newVdom) { destroyDOM(oldVdom); return null; } // 3. Fast path: identical references mean nothing changed if (oldVdom === newVdom) { return newVdom; } // 4. Replace if node types differ if (oldVdom.type !== newVdom.type) { replaceNode(oldVdom, newVdom, parentEl, index); return newVdom; } // 5. Patch based on specific node type switch (newVdom.type) { case DOM_TYPES.TEXT: return patchText(oldVdom, newVdom); case DOM_TYPES.ELEMENT: return patchElement(oldVdom, newVdom); case DOM_TYPES.FRAGMENT: return patchChildren(oldVdom, newVdom); case COMPONENT_TYPE: return patchComponent(oldVdom, newVdom); }}
function patchText(oldVdom, newVdom) { const el = oldVdom.el; newVdom.el = el; // Reuse the same DOM node if (oldVdom.value !== newVdom.value) { el.nodeValue = newVdom.value; // Update text content } return newVdom;}
With keys, GlyphUI can efficiently handle reordering, insertions, and deletions:
function patchKeyedChildren(oldChildren, newChildren, parentEl) { // Build a map of old children by key const oldKeyMap = new Map(); oldChildren.forEach((child, i) => { const key = getNodeKey(child); if (key !== undefined) { oldKeyMap.set(key, { vdom: child, index: i }); } }); const patchedKeys = new Set(); // Patch or mount new children for (let i = 0; i < newChildren.length; i++) { const newChild = newChildren[i]; const newKey = getNodeKey(newChild); const oldEntry = oldKeyMap.get(newKey); if (oldEntry) { // Key found: patch existing node patchDOM(oldEntry.vdom, newChild, parentEl, i); patchedKeys.add(newKey); // Move node if needed if (oldEntry.index < lastPatchedIndex) { parentEl.insertBefore(newChild.el, referenceNode); } } else { // Key not found: mount new node mountDOM(newChild, parentEl, i); } } // Remove old children not in new list oldKeyMap.forEach((oldEntry, key) => { if (!patchedKeys.has(key)) { destroyDOM(oldEntry.vdom); } });}
function removeElementNode(vdom) { const { el, listeners, children } = vdom; // Remove event listeners if (listeners) { removeEventListeners(listeners, el); } // Destroy children if (children) { children.forEach(destroyDOM); } // Remove from DOM el.remove(); vdom.el = null;}