|
2 | 2 | /* Core Functionality */ |
3 | 3 | /* ****************** */ |
4 | 4 |
|
5 | | -import { eventSystem } from "../events"; |
6 | | -import { trackRenderEnd, trackRenderStart } from "../performance"; |
7 | | -import { reconcile } from "../reconciler"; |
| 5 | +import { |
| 6 | + type FiberRoot, |
| 7 | + createRoot as createFiberRoot, |
| 8 | + flushSync, |
| 9 | + updateContainer, |
| 10 | +} from "../fiber"; |
8 | 11 | import { |
9 | 12 | type AnyMiniReactElement, |
10 | 13 | type ElementType, |
11 | 14 | type JSXElementType, |
12 | | - PORTAL, |
13 | 15 | TEXT_ELEMENT, |
14 | | - type VDOMInstance, |
15 | 16 | } from "./types"; |
16 | 17 |
|
17 | | -// Store root instances for each container |
18 | | -const rootInstances = new Map<HTMLElement, VDOMInstance | null>(); |
19 | | -// Store original root elements for re-rendering |
20 | | -const rootElements = new Map<HTMLElement, AnyMiniReactElement | null>(); |
| 18 | +// Store fiber roots for each container |
| 19 | +const fiberRoots = new Map<HTMLElement, FiberRoot>(); |
21 | 20 |
|
22 | 21 | /** |
23 | 22 | * Creates a MiniReact element (virtual DOM node) |
@@ -59,128 +58,49 @@ export function createElement( |
59 | 58 | } |
60 | 59 |
|
61 | 60 | /** |
62 | | - * Renders a MiniReact element into a container using the reconciler |
| 61 | + * Renders a MiniReact element into a container using the fiber reconciler |
63 | 62 | * @param element The element to render (can be null to clear) |
64 | 63 | * @param containerNode The container DOM node |
65 | 64 | */ |
66 | 65 | export function render( |
67 | 66 | element: AnyMiniReactElement | null | undefined, |
68 | 67 | containerNode: HTMLElement, |
69 | 68 | ): void { |
70 | | - // Initialize event system with the container |
71 | | - eventSystem.initialize(containerNode); |
72 | | - |
73 | 69 | const newElement = element || null; |
74 | 70 |
|
75 | | - // Get the old instance BEFORE potentially deleting it |
76 | | - const oldInstance = rootInstances.get(containerNode) || null; |
77 | | - |
78 | | - if (newElement === null) { |
79 | | - // When unmounting, remove original element from map to prevent memory leaks |
80 | | - rootElements.delete(containerNode); |
81 | | - } else { |
82 | | - // Store the original element for re-renders |
83 | | - rootElements.set(containerNode, newElement); |
| 71 | + // Get or create fiber root for this container |
| 72 | + let root = fiberRoots.get(containerNode); |
| 73 | + if (!root) { |
| 74 | + root = createFiberRoot(containerNode); |
| 75 | + fiberRoots.set(containerNode, root); |
84 | 76 | } |
85 | 77 |
|
86 | | - // Track render performance |
87 | | - trackRenderStart(); |
88 | | - const newInstance = reconcile(containerNode, newElement, oldInstance); |
89 | | - trackRenderEnd(); |
| 78 | + // Render tracking is handled inside performSyncWorkOnRoot |
| 79 | + updateContainer(newElement, root); |
| 80 | + flushSync(); |
90 | 81 |
|
91 | 82 | if (newElement === null) { |
92 | | - // Ensure container is completely cleared when rendering null |
93 | | - containerNode.innerHTML = ""; |
94 | | - // Clean up rootInstances after reconciliation |
95 | | - rootInstances.delete(containerNode); |
96 | | - } else { |
97 | | - rootInstances.set(containerNode, newInstance); |
| 83 | + // Clean up fiber root when unmounting |
| 84 | + fiberRoots.delete(containerNode); |
98 | 85 | } |
99 | 86 | } |
100 | 87 |
|
101 | 88 | /** |
102 | | - * Finds the root container for a given VDOM instance |
103 | | - * @param instance The VDOM instance |
104 | | - * @returns The root container element or null |
| 89 | + * Gets the fiber root for a container |
| 90 | + * @param container The container element |
| 91 | + * @returns The fiber root or undefined |
105 | 92 | */ |
106 | | -export function findRootContainer(instance: VDOMInstance): HTMLElement | null { |
107 | | - // Strategy 1: Walk up the parent chain and validate rootContainer references |
108 | | - let current: VDOMInstance | undefined = instance; |
109 | | - let depth = 0; |
110 | | - while (current) { |
111 | | - if (current.rootContainer) { |
112 | | - // Verify this rootContainer is actually a real root by checking our rootInstances map |
113 | | - for (const [container, rootInstance] of rootInstances) { |
114 | | - if (container === current.rootContainer && rootInstance) { |
115 | | - return container; |
116 | | - } |
117 | | - } |
118 | | - } |
119 | | - current = current.parent; |
120 | | - depth++; |
121 | | - if (depth > 10) { |
122 | | - console.warn( |
123 | | - "Parent chain depth exceeded 10, breaking to avoid infinite loop", |
124 | | - ); |
125 | | - break; |
126 | | - } |
127 | | - } |
128 | | - |
129 | | - // Strategy 2: Search through all root instances to find the one containing this instance |
130 | | - for (const [container, rootInstance] of rootInstances) { |
131 | | - if (rootInstance && isInstanceInTree(instance, rootInstance)) { |
132 | | - return container; |
133 | | - } |
134 | | - } |
135 | | - |
136 | | - // Strategy 3: If not found in main trees, check if this instance is part of a portal tree |
137 | | - current = instance; |
138 | | - while (current) { |
139 | | - if ( |
140 | | - current.element && |
141 | | - typeof current.element === "object" && |
142 | | - "type" in current.element && |
143 | | - current.element.type === PORTAL |
144 | | - ) { |
145 | | - // Found a portal parent - now find which root tree contains this portal |
146 | | - for (const [container, rootInstance] of rootInstances) { |
147 | | - if (rootInstance && isInstanceInTree(current, rootInstance)) { |
148 | | - return container; |
149 | | - } |
150 | | - } |
151 | | - } |
152 | | - current = current.parent; |
153 | | - } |
154 | | - |
155 | | - return null; |
| 93 | +export function getFiberRoot(container: HTMLElement): FiberRoot | undefined { |
| 94 | + return fiberRoots.get(container); |
156 | 95 | } |
157 | 96 |
|
158 | | -/** |
159 | | - * Checks if a given instance is part of a VDOM tree |
160 | | - * @param targetInstance The instance to find |
161 | | - * @param rootInstance The root of the tree to search |
162 | | - * @returns True if the instance is in the tree |
163 | | - */ |
164 | | -function isInstanceInTree( |
165 | | - targetInstance: VDOMInstance, |
166 | | - rootInstance: VDOMInstance, |
167 | | -): boolean { |
168 | | - if (targetInstance === rootInstance) { |
169 | | - return true; |
170 | | - } |
| 97 | +// Re-export fiber-based hydration for SSR |
| 98 | +export { hydrateRoot, type HydrateRootOptions } from "../fiber/hydration"; |
171 | 99 |
|
172 | | - return rootInstance.childInstances.some((child) => |
173 | | - isInstanceInTree(targetInstance, child), |
174 | | - ); |
175 | | -} |
176 | | - |
177 | | -/** |
178 | | - * Gets the root element for re-rendering |
179 | | - * @param container The container element |
180 | | - * @returns The root element or null |
181 | | - */ |
182 | | -export function getRootElement( |
183 | | - container: HTMLElement, |
184 | | -): AnyMiniReactElement | null { |
185 | | - return rootElements.get(container) || null; |
186 | | -} |
| 100 | +// Re-export fiber-based resumability for state persistence |
| 101 | +export { |
| 102 | + serializeFiberTree, |
| 103 | + dehydrateRoot, |
| 104 | + parseSerializedRoot, |
| 105 | + type SerializedFiberRoot, |
| 106 | +} from "../fiber/resumability"; |
0 commit comments