nodeRegistry
Low-level DOM node registry for reactive effects and delegated events with automatic cleanup.
API
interface NodeRegistry {
nodes: Map<Node, NodeRegistryItem>;
get(node: Node): NodeRegistryItem;
addEffect(node: Node, effectFn: () => void): void;
addEvent(node: Node, type: string, handler: EventListener): void;
clean(node: Node): void;
observer: MutationObserver;
}
interface NodeRegistryItem {
effects?: Set<() => void>;
events?: Map<string, EventListener>;
}
nodes
Direct access to the internal mapping of DOM nodes to their registry entries.
import { nodeRegistry } from '@hellajs/dom';
const element = document.createElement('div');
nodeRegistry.addEffect(element, () => {});
// Access the internal nodes map
console.log('Total registered nodes:', nodeRegistry.nodes.size);
// Inspect specific node entry
const entry = nodeRegistry.nodes.get(element);
if (entry) {
console.log('Effects:', entry.effects?.size || 0);
console.log('Events:', entry.events?.size || 0);
}
get
Retrieves or creates the registry entry for a DOM node.
import { nodeRegistry } from '@hellajs/dom';
const element = document.createElement('div');
// Get or create registry entry
const registry = nodeRegistry.get(element);
console.log('Effects count:', registry.effects?.size || 0);
console.log('Events count:', registry.events?.size || 0);
// Entry is created if it doesn't exist
const newElement = document.createElement('span');
const newRegistry = nodeRegistry.get(newElement);
console.log('New entry created:', newRegistry);
addEffect
Registers a reactive effect for a DOM node.
import { nodeRegistry } from '@hellajs/dom';
import { signal } from '@hellajs/core';
const element = document.createElement('div');
const count = signal(0);
// Register a reactive effect
nodeRegistry.addEffect(element, () => {
element.textContent = `Count: ${count()}`;
});
// Effect runs automatically when count changes
count(5); // Updates element content
// Multiple effects can be registered
nodeRegistry.addEffect(element, () => {
element.style.color = count() > 10 ? 'red' : 'black';
});
addEvent
Registers an event handler for a DOM node.
import { nodeRegistry } from '@hellajs/dom';
const button = document.createElement('button');
// Register click handler
nodeRegistry.addEvent(button, 'click', (event) => {
console.log('Button clicked!', event.target);
});
// Register multiple event types
nodeRegistry.addEvent(button, 'mouseover', () => {
console.log('Mouse over button');
});
nodeRegistry.addEvent(button, 'mouseout', () => {
console.log('Mouse left button');
});
document.body.appendChild(button);
clean
Manually disposes effects and clears events for a node.
import { nodeRegistry } from '@hellajs/dom';
import { signal } from '@hellajs/core';
const element = document.createElement('div');
const count = signal(0);
// Register effect and event
nodeRegistry.addEffect(element, () => {
element.textContent = `Count: ${count()}`;
});
nodeRegistry.addEvent(element, 'click', () => console.log('Clicked'));
// Manual cleanup (rarely needed)
nodeRegistry.clean(element);
// Node is cleaned up - no more reactive updates
count(10); // Element content won't update
observer
The global MutationObserver instance that monitors DOM changes.
import { nodeRegistry } from '@hellajs/dom';
// Access the global observer
console.log('Observer:', nodeRegistry.observer);
// Check if observer is connected
const isObserving = nodeRegistry.observer !== null;
console.log('Observing DOM changes:', isObserving);
// The observer automatically handles cleanup when nodes are removed
const element = document.createElement('div');
nodeRegistry.addEffect(element, () => {});
document.body.appendChild(element);
element.remove(); // Observer detects removal and cleans up
Key Concepts
Automatic Cleanup
The registry automatically cleans up nodes when they’re removed from the document via a global MutationObserver.
import { nodeRegistry } from '@hellajs/dom';
const element = document.createElement('div');
// Register effects and events
nodeRegistry.addEffect(element, () => { /* ... */ });
nodeRegistry.addEvent(element, 'click', () => { /* ... */ });
// Cleanup happens automatically when removed
document.body.appendChild(element);
element.remove(); // Effects disposed in next microtask
Effect Registration
Reactive effects are stored per node and automatically disposed when the node is removed.
import { nodeRegistry } from '@hellajs/dom';
import { signal } from '@hellajs/core';
const element = document.createElement('div');
const count = signal(0);
nodeRegistry.addEffect(element, () => {
element.textContent = `Count: ${count()}`;
});
Event Handler Management
Event handlers are registered for the global delegation system and cleaned up automatically.
import { nodeRegistry } from '@hellajs/dom';
const button = document.createElement('button');
nodeRegistry.addEvent(button, 'click', (event) => {
console.log('Button clicked!', event);
});
Registry Inspection
Access registry data for debugging and advanced use cases.
import { nodeRegistry } from '@hellajs/dom';
const element = document.createElement('div');
// Get registry entry
const registry = nodeRegistry.get(element);
console.log('Effects count:', registry.effects?.size || 0);
console.log('Events count:', registry.events?.size || 0);
// Direct access to all registered nodes
console.log('Total registered nodes:', nodeRegistry.nodes.size);
Important Considerations
Internal API
This is a low-level API primarily used internally by HellaJS. Most applications should use higher-level APIs like mount
and forEach
.
Memory Management
Manual cleanup is rarely needed since a MutationObserver handles removal detection.
// ✅ Automatic cleanup (recommended)
element.remove(); // Cleanup happens automatically
// ⚠️ Manual cleanup (rarely needed)
nodeRegistry.clean(element);
Observer Coordination
The global MutationObserver watches document.body
with { childList: true, subtree: true }
to detect all node removals. Cleanup runs in microtasks to batch multiple changes efficiently.