kiru 0.45.3 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/appContext.d.ts +0 -13
- package/dist/appContext.d.ts.map +1 -1
- package/dist/appContext.js +15 -55
- package/dist/appContext.js.map +1 -1
- package/dist/constants.d.ts +5 -7
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +5 -7
- package/dist/constants.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +2 -4
- package/dist/context.js.map +1 -1
- package/dist/dom.d.ts +2 -2
- package/dist/dom.d.ts.map +1 -1
- package/dist/dom.js +36 -32
- package/dist/dom.js.map +1 -1
- package/dist/globals.d.ts +1 -6
- package/dist/globals.d.ts.map +1 -1
- package/dist/globals.js +1 -5
- package/dist/globals.js.map +1 -1
- package/dist/hmr.d.ts +1 -1
- package/dist/hmr.d.ts.map +1 -1
- package/dist/hmr.js +2 -4
- package/dist/hmr.js.map +1 -1
- package/dist/hooks/useViewTransition.d.ts.map +1 -1
- package/dist/hooks/useViewTransition.js +3 -3
- package/dist/hooks/useViewTransition.js.map +1 -1
- package/dist/hooks/utils.d.ts +1 -5
- package/dist/hooks/utils.d.ts.map +1 -1
- package/dist/hooks/utils.js +8 -20
- package/dist/hooks/utils.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/lazy.d.ts.map +1 -1
- package/dist/lazy.js +4 -4
- package/dist/lazy.js.map +1 -1
- package/dist/portal.d.ts.map +1 -1
- package/dist/portal.js +2 -3
- package/dist/portal.js.map +1 -1
- package/dist/props.js +1 -1
- package/dist/props.js.map +1 -1
- package/dist/reconciler.d.ts.map +1 -1
- package/dist/reconciler.js +105 -79
- package/dist/reconciler.js.map +1 -1
- package/dist/renderToString.d.ts.map +1 -1
- package/dist/renderToString.js +5 -8
- package/dist/renderToString.js.map +1 -1
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/router.js +5 -6
- package/dist/router/router.js.map +1 -1
- package/dist/scheduler.d.ts +4 -11
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +365 -390
- package/dist/scheduler.js.map +1 -1
- package/dist/signals/base.d.ts +4 -4
- package/dist/signals/base.d.ts.map +1 -1
- package/dist/signals/base.js +38 -24
- package/dist/signals/base.js.map +1 -1
- package/dist/signals/computed.d.ts +2 -2
- package/dist/signals/computed.d.ts.map +1 -1
- package/dist/signals/computed.js +11 -3
- package/dist/signals/computed.js.map +1 -1
- package/dist/signals/effect.d.ts +1 -1
- package/dist/signals/effect.d.ts.map +1 -1
- package/dist/signals/globals.d.ts +2 -2
- package/dist/signals/globals.d.ts.map +1 -1
- package/dist/signals/globals.js.map +1 -1
- package/dist/signals/jsx.d.ts +4 -3
- package/dist/signals/jsx.d.ts.map +1 -1
- package/dist/signals/jsx.js +1 -1
- package/dist/signals/jsx.js.map +1 -1
- package/dist/signals/types.d.ts +2 -2
- package/dist/signals/types.d.ts.map +1 -1
- package/dist/signals/utils.d.ts +1 -1
- package/dist/signals/utils.d.ts.map +1 -1
- package/dist/signals/utils.js +1 -1
- package/dist/signals/utils.js.map +1 -1
- package/dist/ssr/server.d.ts.map +1 -1
- package/dist/ssr/server.js +1 -5
- package/dist/ssr/server.js.map +1 -1
- package/dist/types.d.ts +9 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +17 -17
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/appContext.ts +21 -67
- package/src/constants.ts +8 -7
- package/src/context.ts +2 -4
- package/src/dom.ts +50 -29
- package/src/globals.ts +1 -9
- package/src/hmr.ts +3 -5
- package/src/hooks/useViewTransition.ts +3 -3
- package/src/hooks/utils.ts +7 -22
- package/src/index.ts +3 -3
- package/src/lazy.ts +4 -4
- package/src/portal.ts +2 -3
- package/src/props.ts +1 -1
- package/src/reconciler.ts +116 -90
- package/src/renderToString.ts +5 -8
- package/src/router/router.ts +4 -6
- package/src/scheduler.ts +369 -407
- package/src/signals/base.ts +40 -33
- package/src/signals/computed.ts +8 -3
- package/src/signals/effect.ts +1 -1
- package/src/signals/globals.ts +2 -2
- package/src/signals/jsx.ts +12 -11
- package/src/signals/types.ts +2 -2
- package/src/signals/utils.ts +1 -1
- package/src/ssr/server.ts +1 -5
- package/src/types.ts +9 -2
- package/src/utils.ts +26 -21
- package/dist/flags.d.ts +0 -6
- package/dist/flags.d.ts.map +0 -1
- package/dist/flags.js +0 -16
- package/dist/flags.js.map +0 -1
- package/src/flags.ts +0 -15
package/dist/scheduler.js
CHANGED
|
@@ -1,457 +1,432 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { commitWork, createDom, hydrateDom } from "./dom.js";
|
|
1
|
+
import { $CONTEXT_PROVIDER, CONSECUTIVE_DIRTY_LIMIT, FLAG_DELETION, } from "./constants.js";
|
|
2
|
+
import { commitDeletion, commitWork, createDom, hydrateDom } from "./dom.js";
|
|
4
3
|
import { __DEV__ } from "./env.js";
|
|
5
4
|
import { KiruError } from "./error.js";
|
|
6
|
-
import {
|
|
5
|
+
import { hookIndex, node, renderMode } from "./globals.js";
|
|
7
6
|
import { hydrationStack } from "./hydration.js";
|
|
8
7
|
import { assertValidElementProps } from "./props.js";
|
|
9
8
|
import { reconcileChildren } from "./reconciler.js";
|
|
10
|
-
import { willMemoBlockUpdate, latest, traverseApply, vNodeContains, isExoticType, } from "./utils.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
pendingCallback(deadline);
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
function clear() {
|
|
44
|
-
nextUnitOfWork = null;
|
|
45
|
-
treesInProgress = [];
|
|
46
|
-
currentTreeIndex = 0;
|
|
47
|
-
nextIdleEffects = [];
|
|
48
|
-
deletions = [];
|
|
49
|
-
effectCallbacks = { pre: [], post: [] };
|
|
50
|
-
frameDeadline = 0;
|
|
51
|
-
pendingCallback = null;
|
|
52
|
-
sleep();
|
|
9
|
+
import { willMemoBlockUpdate, latest, traverseApply, vNodeContains, isExoticType, getVNodeAppContext, } from "./utils.js";
|
|
10
|
+
let appCtx;
|
|
11
|
+
let nextUnitOfWork = null;
|
|
12
|
+
let treesInProgress = [];
|
|
13
|
+
let currentTreeIndex = 0;
|
|
14
|
+
let isRunning = false;
|
|
15
|
+
let nextIdleEffects = [];
|
|
16
|
+
let deletions = [];
|
|
17
|
+
let isImmediateEffectsMode = false;
|
|
18
|
+
let immediateEffectDirtiedRender = false;
|
|
19
|
+
let isRenderDirtied = false;
|
|
20
|
+
let consecutiveDirtyCount = 0;
|
|
21
|
+
let pendingContextChanges = new Set();
|
|
22
|
+
let preEffects = [];
|
|
23
|
+
let postEffects = [];
|
|
24
|
+
export function nextIdle(fn, wakeUpIfIdle = true) {
|
|
25
|
+
nextIdleEffects.push(fn);
|
|
26
|
+
if (wakeUpIfIdle)
|
|
27
|
+
wake();
|
|
28
|
+
}
|
|
29
|
+
export function flushSync() {
|
|
30
|
+
workLoop();
|
|
31
|
+
}
|
|
32
|
+
export function requestUpdate(vNode) {
|
|
33
|
+
if (vNode.flags & FLAG_DELETION)
|
|
34
|
+
return;
|
|
35
|
+
if (__DEV__) {
|
|
36
|
+
// if (options?.debug?.onRequestUpdate) {
|
|
37
|
+
// options.debug.onRequestUpdate(vNode)
|
|
38
|
+
// }
|
|
53
39
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
requestIdleCallback(workLoop);
|
|
40
|
+
if (renderMode.current === "hydrate") {
|
|
41
|
+
return nextIdle(() => {
|
|
42
|
+
vNode.flags & FLAG_DELETION || queueUpdate(vNode);
|
|
43
|
+
});
|
|
59
44
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
45
|
+
queueUpdate(vNode);
|
|
46
|
+
}
|
|
47
|
+
export function requestDelete(vNode) {
|
|
48
|
+
if (vNode.flags & FLAG_DELETION)
|
|
49
|
+
return;
|
|
50
|
+
if (renderMode.current === "hydrate") {
|
|
51
|
+
return nextIdle(() => {
|
|
52
|
+
vNode.flags & FLAG_DELETION || queueDelete(vNode);
|
|
53
|
+
});
|
|
66
54
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
55
|
+
queueDelete(vNode);
|
|
56
|
+
}
|
|
57
|
+
function queueWorkLoop() {
|
|
58
|
+
queueMicrotask(workLoop);
|
|
59
|
+
}
|
|
60
|
+
function wake() {
|
|
61
|
+
if (isRunning)
|
|
62
|
+
return;
|
|
63
|
+
isRunning = true;
|
|
64
|
+
queueWorkLoop();
|
|
65
|
+
}
|
|
66
|
+
function sleep() {
|
|
67
|
+
isRunning = false;
|
|
68
|
+
}
|
|
69
|
+
function queueUpdate(vNode) {
|
|
70
|
+
// In immediate effect mode (useLayoutEffect), immediately mark the render as dirty
|
|
71
|
+
if (isImmediateEffectsMode) {
|
|
72
|
+
immediateEffectDirtiedRender = true;
|
|
71
73
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
// If this node is currently being rendered, just mark it dirty
|
|
75
|
+
if (node.current === vNode) {
|
|
76
|
+
if (__DEV__) {
|
|
77
|
+
window.__kiru?.profilingContext?.emit("updateDirtied", appCtx);
|
|
76
78
|
}
|
|
77
|
-
|
|
79
|
+
isRenderDirtied = true;
|
|
80
|
+
return;
|
|
78
81
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
// If it's already the next unit of work, no need to queue again
|
|
83
|
+
if (nextUnitOfWork === vNode) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (nextUnitOfWork === null) {
|
|
87
|
+
treesInProgress.push(vNode);
|
|
88
|
+
nextUnitOfWork = vNode;
|
|
89
|
+
return wake();
|
|
90
|
+
}
|
|
91
|
+
for (let i = 0; i < treesInProgress.length; i++) {
|
|
92
|
+
const tree = treesInProgress[i];
|
|
93
|
+
if (tree !== vNode)
|
|
94
|
+
continue;
|
|
95
|
+
if (i < currentTreeIndex) {
|
|
96
|
+
// It was already processed; requeue it to the end
|
|
97
|
+
currentTreeIndex--;
|
|
98
|
+
treesInProgress.splice(i, 1);
|
|
99
|
+
treesInProgress.push(tree);
|
|
91
100
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Check if this node is a descendant of any trees already queued
|
|
104
|
+
for (let i = 0; i < treesInProgress.length; i++) {
|
|
105
|
+
const tree = treesInProgress[i];
|
|
106
|
+
if (!vNodeContains(tree, vNode))
|
|
107
|
+
continue;
|
|
108
|
+
if (i === currentTreeIndex) {
|
|
109
|
+
// It's a child of the currently worked-on tree
|
|
110
|
+
// If it's deeper within the same tree, we can skip
|
|
111
|
+
if (vNodeContains(nextUnitOfWork, vNode))
|
|
112
|
+
return;
|
|
113
|
+
// If it's not in the current work subtree, move back up to it
|
|
114
|
+
nextUnitOfWork = vNode;
|
|
95
115
|
}
|
|
96
|
-
if (
|
|
116
|
+
else if (i < currentTreeIndex) {
|
|
117
|
+
// It's a descendant of an already processed tree; treat as a new update
|
|
97
118
|
treesInProgress.push(vNode);
|
|
98
|
-
nextUnitOfWork = vNode;
|
|
99
|
-
return wake();
|
|
100
119
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
currentTreeIndex--;
|
|
112
|
-
treesInProgress.splice(treeIdx, 1);
|
|
113
|
-
treesInProgress.push(vNode);
|
|
114
|
-
}
|
|
115
|
-
return;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// Check if this node contains any of the currently queued trees
|
|
123
|
+
let didReplaceTree = false;
|
|
124
|
+
let shouldQueueAtEnd = false;
|
|
125
|
+
for (let i = 0; i < treesInProgress.length;) {
|
|
126
|
+
const tree = treesInProgress[i];
|
|
127
|
+
if (!vNodeContains(vNode, tree)) {
|
|
128
|
+
i++;
|
|
129
|
+
continue;
|
|
116
130
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (tree.depth > nodeDepth)
|
|
122
|
-
continue; // Can't be an ancestor
|
|
123
|
-
if (!vNodeContains(tree, vNode))
|
|
124
|
-
continue;
|
|
125
|
-
if (i === currentTreeIndex) {
|
|
126
|
-
// It's a child of the currently worked-on tree
|
|
127
|
-
// If it's deeper within the same tree, we can skip
|
|
128
|
-
if (vNodeContains(nextUnitOfWork, vNode))
|
|
129
|
-
return;
|
|
130
|
-
// If it's not in the current work subtree, move back up to it
|
|
131
|
+
// This node contains another update root, replace it
|
|
132
|
+
if (i === currentTreeIndex) {
|
|
133
|
+
if (!didReplaceTree) {
|
|
134
|
+
treesInProgress.splice(i, 1, vNode);
|
|
131
135
|
nextUnitOfWork = vNode;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// It's a descendant of an already processed tree; treat as a new update
|
|
135
|
-
treesInProgress.push(vNode);
|
|
136
|
-
}
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
// Check if this node contains any of the currently queued trees
|
|
140
|
-
let didReplaceTree = false;
|
|
141
|
-
let shouldQueueAtEnd = false;
|
|
142
|
-
for (let i = 0; i < treesInProgress.length;) {
|
|
143
|
-
const tree = treesInProgress[i];
|
|
144
|
-
if (tree.depth < nodeDepth || !vNodeContains(vNode, tree)) {
|
|
145
|
-
i++;
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
// This node contains another update root, replace it
|
|
149
|
-
if (i === currentTreeIndex) {
|
|
150
|
-
if (!didReplaceTree) {
|
|
151
|
-
treesInProgress.splice(i, 1, vNode);
|
|
152
|
-
nextUnitOfWork = vNode;
|
|
153
|
-
didReplaceTree = true;
|
|
154
|
-
i++; // advance past replaced node
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
treesInProgress.splice(i, 1);
|
|
158
|
-
// no increment
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
else if (i < currentTreeIndex) {
|
|
162
|
-
currentTreeIndex--;
|
|
163
|
-
treesInProgress.splice(i, 1);
|
|
164
|
-
if (!didReplaceTree) {
|
|
165
|
-
shouldQueueAtEnd = true;
|
|
166
|
-
didReplaceTree = true;
|
|
167
|
-
}
|
|
168
|
-
// no increment
|
|
136
|
+
didReplaceTree = true;
|
|
137
|
+
i++; // advance past replaced node
|
|
169
138
|
}
|
|
170
139
|
else {
|
|
171
|
-
// i > currentTreeIndex
|
|
172
140
|
treesInProgress.splice(i, 1);
|
|
173
|
-
if (!didReplaceTree) {
|
|
174
|
-
shouldQueueAtEnd = true;
|
|
175
|
-
didReplaceTree = true;
|
|
176
|
-
}
|
|
177
141
|
// no increment
|
|
178
142
|
}
|
|
179
143
|
}
|
|
180
|
-
if (
|
|
181
|
-
|
|
144
|
+
else if (i < currentTreeIndex) {
|
|
145
|
+
currentTreeIndex--;
|
|
146
|
+
treesInProgress.splice(i, 1);
|
|
147
|
+
if (!didReplaceTree) {
|
|
148
|
+
shouldQueueAtEnd = true;
|
|
149
|
+
didReplaceTree = true;
|
|
150
|
+
}
|
|
151
|
+
// no increment
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// i > currentTreeIndex
|
|
155
|
+
treesInProgress.splice(i, 1);
|
|
156
|
+
if (!didReplaceTree) {
|
|
157
|
+
shouldQueueAtEnd = true;
|
|
158
|
+
didReplaceTree = true;
|
|
159
|
+
}
|
|
160
|
+
// no increment
|
|
182
161
|
}
|
|
183
|
-
// If it doesn't overlap with any queued tree, queue as new independent update root
|
|
184
|
-
treesInProgress.push(vNode);
|
|
185
|
-
}
|
|
186
|
-
function queueDelete(vNode) {
|
|
187
|
-
traverseApply(vNode, (n) => (n.flags = flags.set(n.flags, FLAG.DELETION)));
|
|
188
|
-
deletions.push(vNode);
|
|
189
162
|
}
|
|
190
|
-
|
|
191
|
-
return
|
|
163
|
+
if (!shouldQueueAtEnd && didReplaceTree) {
|
|
164
|
+
return;
|
|
192
165
|
}
|
|
193
|
-
|
|
194
|
-
|
|
166
|
+
// If it doesn't overlap with any queued tree, queue as new independent update root
|
|
167
|
+
treesInProgress.push(vNode);
|
|
168
|
+
}
|
|
169
|
+
function queueDelete(vNode) {
|
|
170
|
+
traverseApply(vNode, (n) => (n.flags |= FLAG_DELETION));
|
|
171
|
+
deletions.push(vNode);
|
|
172
|
+
}
|
|
173
|
+
function workLoop() {
|
|
174
|
+
if (__DEV__) {
|
|
175
|
+
const n = nextUnitOfWork ?? deletions[0] ?? treesInProgress[0];
|
|
176
|
+
if (n) {
|
|
177
|
+
appCtx = getVNodeAppContext(n);
|
|
195
178
|
window.__kiru?.profilingContext?.beginTick(appCtx);
|
|
196
179
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
nextUnitOfWork =
|
|
200
|
-
performUnitOfWork(nextUnitOfWork) ??
|
|
201
|
-
treesInProgress[++currentTreeIndex] ??
|
|
202
|
-
queueBlockedContextDependencyRoots();
|
|
203
|
-
if ((deadline?.timeRemaining() ?? 1) < 1)
|
|
204
|
-
break;
|
|
180
|
+
else {
|
|
181
|
+
appCtx = null;
|
|
205
182
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
isImmediateEffectsMode = true;
|
|
217
|
-
flushEffects(effectCallbacks.pre);
|
|
218
|
-
isImmediateEffectsMode = false;
|
|
219
|
-
if (immediateEffectDirtiedRender) {
|
|
220
|
-
checkForTooManyConsecutiveDirtyRenders();
|
|
221
|
-
flushEffects(effectCallbacks.post);
|
|
222
|
-
immediateEffectDirtiedRender = false;
|
|
223
|
-
consecutiveDirtyCount++;
|
|
224
|
-
if (__DEV__) {
|
|
225
|
-
window.__kiru?.profilingContext?.endTick(appCtx);
|
|
226
|
-
window.__kiru?.profilingContext?.emit("updateDirtied", appCtx);
|
|
227
|
-
}
|
|
228
|
-
return workLoop();
|
|
229
|
-
}
|
|
230
|
-
consecutiveDirtyCount = 0;
|
|
231
|
-
flushEffects(effectCallbacks.post);
|
|
232
|
-
window.__kiru.emit("update", appCtx);
|
|
233
|
-
if (__DEV__) {
|
|
234
|
-
window.__kiru?.profilingContext?.emit("update", appCtx);
|
|
235
|
-
}
|
|
183
|
+
}
|
|
184
|
+
while (nextUnitOfWork) {
|
|
185
|
+
nextUnitOfWork =
|
|
186
|
+
performUnitOfWork(nextUnitOfWork) ??
|
|
187
|
+
treesInProgress[++currentTreeIndex] ??
|
|
188
|
+
queueBlockedContextDependencyRoots();
|
|
189
|
+
}
|
|
190
|
+
if (!nextUnitOfWork && (deletions.length || treesInProgress.length)) {
|
|
191
|
+
while (deletions.length) {
|
|
192
|
+
commitDeletion(deletions.shift());
|
|
236
193
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
194
|
+
const workRoots = [...treesInProgress];
|
|
195
|
+
treesInProgress.length = 0;
|
|
196
|
+
currentTreeIndex = 0;
|
|
197
|
+
for (const root of workRoots) {
|
|
198
|
+
commitWork(root);
|
|
199
|
+
}
|
|
200
|
+
isImmediateEffectsMode = true;
|
|
201
|
+
flushEffects(preEffects);
|
|
202
|
+
isImmediateEffectsMode = false;
|
|
203
|
+
if (immediateEffectDirtiedRender) {
|
|
204
|
+
checkForTooManyConsecutiveDirtyRenders();
|
|
205
|
+
flushEffects(postEffects);
|
|
206
|
+
immediateEffectDirtiedRender = false;
|
|
207
|
+
consecutiveDirtyCount++;
|
|
242
208
|
if (__DEV__) {
|
|
243
209
|
window.__kiru?.profilingContext?.endTick(appCtx);
|
|
210
|
+
window.__kiru?.profilingContext?.emit("updateDirtied", appCtx);
|
|
244
211
|
}
|
|
245
|
-
return;
|
|
212
|
+
return flushSync();
|
|
213
|
+
}
|
|
214
|
+
consecutiveDirtyCount = 0;
|
|
215
|
+
flushEffects(postEffects);
|
|
216
|
+
if (__DEV__) {
|
|
217
|
+
window.__kiru.emit("update", appCtx);
|
|
218
|
+
window.__kiru?.profilingContext?.emit("update", appCtx);
|
|
246
219
|
}
|
|
247
|
-
requestIdleCallback(workLoop);
|
|
248
220
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
221
|
+
if (!nextUnitOfWork) {
|
|
222
|
+
sleep();
|
|
223
|
+
while (nextIdleEffects.length) {
|
|
224
|
+
nextIdleEffects.shift()();
|
|
225
|
+
}
|
|
226
|
+
if (__DEV__) {
|
|
227
|
+
if (appCtx) {
|
|
228
|
+
window.__kiru?.profilingContext?.endTick(appCtx);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return;
|
|
255
232
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
if (depDepth < rootDepth && vNodeContains(dep, root)) {
|
|
279
|
-
jobRoots[i] = dep;
|
|
280
|
-
return;
|
|
233
|
+
queueWorkLoop();
|
|
234
|
+
}
|
|
235
|
+
function queueBlockedContextDependencyRoots() {
|
|
236
|
+
if (pendingContextChanges.size === 0)
|
|
237
|
+
return null;
|
|
238
|
+
// TODO: it's possible that a 'job' created by this process is
|
|
239
|
+
// blocked by a parent memo after a queueUpdate -> replaceTree action.
|
|
240
|
+
// To prevent this, we might need to add these to a distinct queue.
|
|
241
|
+
const jobRoots = [];
|
|
242
|
+
pendingContextChanges.forEach((provider) => {
|
|
243
|
+
provider.props.dependents.forEach((dep) => {
|
|
244
|
+
if (!willMemoBlockUpdate(provider, dep))
|
|
245
|
+
return;
|
|
246
|
+
for (let i = 0; i < jobRoots.length; i++) {
|
|
247
|
+
const root = jobRoots[i];
|
|
248
|
+
if (vNodeContains(root, dep)) {
|
|
249
|
+
if (willMemoBlockUpdate(root, dep)) {
|
|
250
|
+
// root is a parent of dep and there's a memo between them, prevent consolidation and queue as new root
|
|
251
|
+
break;
|
|
281
252
|
}
|
|
253
|
+
return;
|
|
282
254
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
pendingContextChanges.clear();
|
|
287
|
-
treesInProgress.push(...jobRoots);
|
|
288
|
-
return jobRoots[0] ?? null;
|
|
289
|
-
}
|
|
290
|
-
function performUnitOfWork(vNode) {
|
|
291
|
-
let renderChild = true;
|
|
292
|
-
try {
|
|
293
|
-
const { props } = vNode;
|
|
294
|
-
if (typeof vNode.type === "string") {
|
|
295
|
-
updateHostComponent(vNode);
|
|
296
|
-
}
|
|
297
|
-
else if (isExoticType(vNode.type)) {
|
|
298
|
-
if (vNode.type === $CONTEXT_PROVIDER) {
|
|
299
|
-
const asProvider = vNode;
|
|
300
|
-
const { dependents, value } = asProvider.props;
|
|
301
|
-
if (dependents.size &&
|
|
302
|
-
asProvider.prev &&
|
|
303
|
-
asProvider.prev.props.value !== value) {
|
|
304
|
-
pendingContextChanges.add(asProvider);
|
|
305
|
-
}
|
|
255
|
+
if (vNodeContains(dep, root)) {
|
|
256
|
+
jobRoots[i] = dep;
|
|
257
|
+
return;
|
|
306
258
|
}
|
|
307
|
-
vNode.child = reconcileChildren(vNode, props.children);
|
|
308
|
-
vNode.deletions?.forEach((d) => queueDelete(d));
|
|
309
|
-
}
|
|
310
|
-
else {
|
|
311
|
-
renderChild = updateFunctionComponent(vNode);
|
|
312
259
|
}
|
|
260
|
+
jobRoots.push(dep);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
pendingContextChanges.clear();
|
|
264
|
+
treesInProgress.push(...jobRoots);
|
|
265
|
+
return jobRoots[0] ?? null;
|
|
266
|
+
}
|
|
267
|
+
function performUnitOfWork(vNode) {
|
|
268
|
+
let renderChild = true;
|
|
269
|
+
try {
|
|
270
|
+
const { props } = vNode;
|
|
271
|
+
if (typeof vNode.type === "string") {
|
|
272
|
+
updateHostComponent(vNode);
|
|
313
273
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (error.fatal) {
|
|
323
|
-
throw error;
|
|
274
|
+
else if (isExoticType(vNode.type)) {
|
|
275
|
+
if (vNode.type === $CONTEXT_PROVIDER) {
|
|
276
|
+
const asProvider = vNode;
|
|
277
|
+
const { dependents, value } = asProvider.props;
|
|
278
|
+
if (dependents.size &&
|
|
279
|
+
asProvider.prev &&
|
|
280
|
+
asProvider.prev.props.value !== value) {
|
|
281
|
+
pendingContextChanges.add(asProvider);
|
|
324
282
|
}
|
|
325
|
-
console.error(error);
|
|
326
|
-
return;
|
|
327
283
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
});
|
|
284
|
+
vNode.child = reconcileChildren(vNode, props.children);
|
|
285
|
+
queueNodeChildDeletions(vNode);
|
|
331
286
|
}
|
|
332
|
-
|
|
333
|
-
|
|
287
|
+
else {
|
|
288
|
+
renderChild = updateFunctionComponent(vNode);
|
|
334
289
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
346
|
-
if (nextNode === treesInProgress[currentTreeIndex])
|
|
347
|
-
return;
|
|
348
|
-
if (nextNode.sibling) {
|
|
349
|
-
return nextNode.sibling;
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
if (__DEV__) {
|
|
293
|
+
window.__kiru?.emit("error", appCtx, error instanceof Error ? error : new Error(String(error)));
|
|
294
|
+
}
|
|
295
|
+
if (KiruError.isKiruError(error)) {
|
|
296
|
+
if (error.customNodeStack) {
|
|
297
|
+
setTimeout(() => {
|
|
298
|
+
throw new Error(error.customNodeStack);
|
|
299
|
+
});
|
|
350
300
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
hydrationStack.pop();
|
|
301
|
+
if (error.fatal) {
|
|
302
|
+
throw error;
|
|
354
303
|
}
|
|
304
|
+
console.error(error);
|
|
305
|
+
return;
|
|
355
306
|
}
|
|
307
|
+
setTimeout(() => {
|
|
308
|
+
throw error;
|
|
309
|
+
});
|
|
356
310
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
311
|
+
if (renderChild && vNode.child) {
|
|
312
|
+
return vNode.child;
|
|
313
|
+
}
|
|
314
|
+
let nextNode = vNode;
|
|
315
|
+
while (nextNode) {
|
|
316
|
+
// queue effects upon ascent
|
|
317
|
+
if (nextNode.immediateEffects) {
|
|
318
|
+
preEffects.push(...nextNode.immediateEffects);
|
|
319
|
+
nextNode.immediateEffects = undefined;
|
|
366
320
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* remove previous signal subscriptions (if any) every render.
|
|
377
|
-
* this prevents no-longer-observed signals from triggering updates
|
|
378
|
-
* in components that are not currently using them.
|
|
379
|
-
*
|
|
380
|
-
* TODO: in future, we might be able to optimize this by
|
|
381
|
-
* only clearing the subscriptions that are no longer needed
|
|
382
|
-
* and not clearing the entire set.
|
|
383
|
-
*/
|
|
384
|
-
if (subs) {
|
|
385
|
-
for (const sub of subs) {
|
|
386
|
-
Signal.unsubscribe(vNode, sub);
|
|
387
|
-
}
|
|
388
|
-
subs.clear();
|
|
389
|
-
}
|
|
390
|
-
if (__DEV__) {
|
|
391
|
-
newChild = latest(type)(props);
|
|
392
|
-
delete vNode.hmrUpdated;
|
|
393
|
-
if (++renderTryCount > CONSECUTIVE_DIRTY_LIMIT) {
|
|
394
|
-
throw new KiruError({
|
|
395
|
-
message: "Too many re-renders. Kiru limits the number of renders to prevent an infinite loop.",
|
|
396
|
-
fatal: true,
|
|
397
|
-
vNode,
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
continue;
|
|
401
|
-
}
|
|
402
|
-
newChild = type(props);
|
|
403
|
-
} while (isRenderDirtied);
|
|
404
|
-
vNode.child = reconcileChildren(vNode, newChild);
|
|
405
|
-
vNode.deletions?.forEach((d) => queueDelete(d));
|
|
406
|
-
return true;
|
|
321
|
+
if (nextNode.effects) {
|
|
322
|
+
postEffects.push(...nextNode.effects);
|
|
323
|
+
nextNode.effects = undefined;
|
|
324
|
+
}
|
|
325
|
+
if (nextNode === treesInProgress[currentTreeIndex])
|
|
326
|
+
return;
|
|
327
|
+
if (nextNode.sibling) {
|
|
328
|
+
return nextNode.sibling;
|
|
407
329
|
}
|
|
408
|
-
|
|
409
|
-
|
|
330
|
+
nextNode = nextNode.parent;
|
|
331
|
+
if (renderMode.current === "hydrate" && nextNode?.dom) {
|
|
332
|
+
hydrationStack.pop();
|
|
410
333
|
}
|
|
411
334
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
335
|
+
}
|
|
336
|
+
function updateFunctionComponent(vNode) {
|
|
337
|
+
const { type, props, subs, prev, isMemoized } = vNode;
|
|
338
|
+
if (isMemoized) {
|
|
339
|
+
vNode.memoizedProps = props;
|
|
340
|
+
if (prev?.memoizedProps &&
|
|
341
|
+
vNode.arePropsEqual(prev.memoizedProps, props) &&
|
|
342
|
+
!vNode.hmrUpdated) {
|
|
343
|
+
return false;
|
|
416
344
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
345
|
+
}
|
|
346
|
+
try {
|
|
347
|
+
node.current = vNode;
|
|
348
|
+
let newChild;
|
|
349
|
+
let renderTryCount = 0;
|
|
350
|
+
do {
|
|
351
|
+
isRenderDirtied = false;
|
|
352
|
+
hookIndex.current = 0;
|
|
353
|
+
/**
|
|
354
|
+
* remove previous signal subscriptions (if any) every render.
|
|
355
|
+
* this prevents no-longer-observed signals from triggering updates
|
|
356
|
+
* in components that are not currently using them.
|
|
357
|
+
*
|
|
358
|
+
* TODO: in future, we might be able to optimize this by
|
|
359
|
+
* only clearing the subscriptions that are no longer needed
|
|
360
|
+
* and not clearing the entire set.
|
|
361
|
+
*/
|
|
362
|
+
if (subs) {
|
|
363
|
+
subs.forEach((unsub) => unsub());
|
|
364
|
+
subs.clear();
|
|
423
365
|
}
|
|
424
366
|
if (__DEV__) {
|
|
425
|
-
|
|
426
|
-
vNode.
|
|
367
|
+
newChild = latest(type)(props);
|
|
368
|
+
delete vNode.hmrUpdated;
|
|
369
|
+
if (++renderTryCount > CONSECUTIVE_DIRTY_LIMIT) {
|
|
370
|
+
throw new KiruError({
|
|
371
|
+
message: "Too many re-renders. Kiru limits the number of renders to prevent an infinite loop.",
|
|
372
|
+
fatal: true,
|
|
373
|
+
vNode,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
continue;
|
|
427
377
|
}
|
|
378
|
+
newChild = type(props);
|
|
379
|
+
} while (isRenderDirtied);
|
|
380
|
+
vNode.child = reconcileChildren(vNode, newChild);
|
|
381
|
+
queueNodeChildDeletions(vNode);
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
finally {
|
|
385
|
+
node.current = null;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
function updateHostComponent(vNode) {
|
|
389
|
+
const { props, type } = vNode;
|
|
390
|
+
if (__DEV__) {
|
|
391
|
+
assertValidElementProps(vNode);
|
|
392
|
+
}
|
|
393
|
+
if (!vNode.dom) {
|
|
394
|
+
if (renderMode.current === "hydrate") {
|
|
395
|
+
hydrateDom(vNode);
|
|
428
396
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
397
|
+
else {
|
|
398
|
+
vNode.dom = createDom(vNode);
|
|
399
|
+
}
|
|
400
|
+
if (__DEV__) {
|
|
401
|
+
if (vNode.dom instanceof Element) {
|
|
402
|
+
vNode.dom.__kiruNode = vNode;
|
|
403
|
+
}
|
|
433
404
|
}
|
|
405
|
+
}
|
|
406
|
+
// text should _never_ have children
|
|
407
|
+
if (type !== "#text") {
|
|
408
|
+
vNode.child = reconcileChildren(vNode, props.children);
|
|
409
|
+
queueNodeChildDeletions(vNode);
|
|
434
410
|
if (vNode.child && renderMode.current === "hydrate") {
|
|
435
411
|
hydrationStack.push(vNode.dom);
|
|
436
412
|
}
|
|
437
413
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
414
|
+
}
|
|
415
|
+
function queueNodeChildDeletions(vNode) {
|
|
416
|
+
if (vNode.deletions) {
|
|
417
|
+
vNode.deletions.forEach(queueDelete);
|
|
418
|
+
vNode.deletions = null;
|
|
442
419
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
420
|
+
}
|
|
421
|
+
function checkForTooManyConsecutiveDirtyRenders() {
|
|
422
|
+
if (consecutiveDirtyCount > CONSECUTIVE_DIRTY_LIMIT) {
|
|
423
|
+
throw new KiruError("Maximum update depth exceeded. This can happen when a component repeatedly calls setState during render or in useLayoutEffect. Kiru limits the number of nested updates to prevent infinite loops.");
|
|
446
424
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
queueUpdate,
|
|
454
|
-
queueDelete,
|
|
455
|
-
});
|
|
425
|
+
}
|
|
426
|
+
function flushEffects(effectArr) {
|
|
427
|
+
for (let i = 0; i < effectArr.length; i++) {
|
|
428
|
+
effectArr[i]();
|
|
429
|
+
}
|
|
430
|
+
effectArr.length = 0;
|
|
456
431
|
}
|
|
457
432
|
//# sourceMappingURL=scheduler.js.map
|