Component Lifecycles & Memory Management
Unlike frameworks such as React or Svelte, CellUI does not have a "Virtual DOM" or a complex component lifecycle. A CellUI component is simply a function that returns a DocumentFragment. It executes exactly once.
This means there are no onMount, onUpdate, or useEffect(..., []) dependencies to track.
The Problem: Teardown
Because CellUI components run once, they are incredibly fast. However, this creates a challenge when a component is removed from the DOM.
Consider this scenario using a third-party library like Chart.js:
function ChartCanvas() {
const canvasRef = signal<HTMLCanvasElement | null>(null);
// This effect runs when the canvasRef is populated by the DOM parser
effect(() => {
if (canvasRef.value) {
const chartInstance = new Chart(canvasRef.value, { /* ...config... */ });
// HOW DO WE DESTROY `chartInstance` WHEN THE WIDGET UNMOUNTS?
}
});
return view`<canvas ref="${canvasRef}"></canvas>`;
}If a parent component uses when() to conditionally remove ChartCanvas(), CellUI instantly removes the element from the document.
However, the Chart instance still exists in JavaScript's memory because the effect() closure maintains a reference to it. This is a memory leak.
Current Constraints & Workarounds
CellUI's core philosophy mandates that the Real DOM is the source of truth. As such, CellUI currently lacks an explicit onCleanup hook built into the framework because we do not track a Virtual Component Tree that "unmounts."
The Workaround: If you are building heavily dynamic dashboards with expensive third-party library instantiations, you must manually track cleanup logic, or rely on native browser APIs like MutationObserver to watch when the canvas node is removed from the document.body.
function ChartCanvas() {
const canvasRef = signal<HTMLCanvasElement | null>(null);
effect(() => {
if (canvasRef.value) {
const chartInstance = new Chart(canvasRef.value, { /* ... */ });
// Manual cleanup observation
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
Array.from(mutation.removedNodes).forEach((node) => {
if (node === canvasRef.value) {
chartInstance.destroy(); // Safely clean up memory
observer.disconnect();
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
}
});
return view`<canvas ref="${canvasRef}"></canvas>`;
}The Future of CellUI
The CellUI team recognizes that relying on MutationObserver is boilerplate-heavy text. A native onCleanup(node, callback) primitive is a high priority for future framework iterations.