kiru 0.54.0-preview.0 → 0.54.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/components/memo.d.ts +1 -3
- package/dist/components/memo.d.ts.map +1 -1
- package/dist/components/memo.js +2 -2
- package/dist/components/memo.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +1 -23
- package/dist/context.js.map +1 -1
- package/dist/dom.d.ts.map +1 -1
- package/dist/dom.js +109 -72
- package/dist/dom.js.map +1 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +2 -4
- package/dist/error.js.map +1 -1
- package/dist/form/index.d.ts.map +1 -1
- package/dist/form/index.js +6 -10
- package/dist/form/index.js.map +1 -1
- package/dist/globals.d.ts +1 -1
- package/dist/globals.d.ts.map +1 -1
- package/dist/globals.js.map +1 -1
- package/dist/hmr.d.ts +1 -0
- package/dist/hmr.d.ts.map +1 -1
- package/dist/hmr.js +11 -3
- package/dist/hmr.js.map +1 -1
- package/dist/hooks/useEffectEvent.d.ts.map +1 -1
- package/dist/hooks/useEffectEvent.js.map +1 -1
- package/dist/hooks/usePromise.d.ts.map +1 -1
- package/dist/hooks/usePromise.js.map +1 -1
- package/dist/hooks/utils.d.ts.map +1 -1
- package/dist/hooks/utils.js +10 -10
- package/dist/hooks/utils.js.map +1 -1
- package/dist/hydration.d.ts +6 -13
- package/dist/hydration.d.ts.map +1 -1
- package/dist/hydration.js +20 -50
- package/dist/hydration.js.map +1 -1
- package/dist/reconciler.d.ts.map +1 -1
- package/dist/reconciler.js +3 -6
- package/dist/reconciler.js.map +1 -1
- package/dist/recursiveRender.d.ts.map +1 -1
- package/dist/recursiveRender.js +9 -8
- package/dist/recursiveRender.js.map +1 -1
- package/dist/renderToString.d.ts.map +1 -1
- package/dist/renderToString.js.map +1 -1
- package/dist/router/client/index.d.ts +2 -4
- package/dist/router/client/index.d.ts.map +1 -1
- package/dist/router/client/index.js +11 -49
- package/dist/router/client/index.js.map +1 -1
- package/dist/router/context.d.ts +5 -2
- package/dist/router/context.d.ts.map +1 -1
- package/dist/router/context.js +1 -5
- package/dist/router/context.js.map +1 -1
- package/dist/router/fileRouter.d.ts.map +1 -1
- package/dist/router/fileRouter.js +2 -4
- package/dist/router/fileRouter.js.map +1 -1
- package/dist/router/fileRouterController.d.ts +2 -2
- package/dist/router/fileRouterController.d.ts.map +1 -1
- package/dist/router/fileRouterController.js +39 -101
- package/dist/router/fileRouterController.js.map +1 -1
- package/dist/router/globals.d.ts +0 -3
- package/dist/router/globals.d.ts.map +1 -1
- package/dist/router/globals.js +0 -3
- package/dist/router/globals.js.map +1 -1
- package/dist/router/head.d.ts.map +1 -1
- package/dist/router/head.js +7 -5
- package/dist/router/head.js.map +1 -1
- package/dist/router/index.d.ts +1 -2
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +1 -2
- package/dist/router/index.js.map +1 -1
- package/dist/router/link.js +3 -3
- package/dist/router/link.js.map +1 -1
- package/dist/router/{ssg → server}/index.d.ts +3 -4
- package/dist/router/server/index.d.ts.map +1 -0
- package/dist/router/{ssg → server}/index.js +5 -8
- package/dist/router/server/index.js.map +1 -0
- package/dist/router/types.d.ts +4 -37
- package/dist/router/types.d.ts.map +1 -1
- package/dist/router/types.internal.d.ts +0 -4
- package/dist/router/types.internal.d.ts.map +1 -1
- package/dist/router/utils/index.d.ts +3 -8
- package/dist/router/utils/index.d.ts.map +1 -1
- package/dist/router/utils/index.js +8 -40
- package/dist/router/utils/index.js.map +1 -1
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +60 -53
- package/dist/scheduler.js.map +1 -1
- package/dist/signals/base.d.ts +0 -2
- package/dist/signals/base.d.ts.map +1 -1
- package/dist/signals/base.js +0 -6
- package/dist/signals/base.js.map +1 -1
- package/dist/signals/computed.d.ts +3 -0
- package/dist/signals/computed.d.ts.map +1 -1
- package/dist/signals/computed.js +29 -20
- package/dist/signals/computed.js.map +1 -1
- package/dist/signals/for.d.ts +3 -3
- package/dist/signals/for.d.ts.map +1 -1
- package/dist/signals/for.js +2 -1
- package/dist/signals/for.js.map +1 -1
- package/dist/signals/utils.d.ts.map +1 -1
- package/dist/signals/utils.js +2 -1
- package/dist/signals/utils.js.map +1 -1
- package/dist/signals/watch.d.ts.map +1 -1
- package/dist/signals/watch.js +18 -22
- package/dist/signals/watch.js.map +1 -1
- package/dist/ssr/client.d.ts +1 -1
- package/dist/ssr/client.d.ts.map +1 -1
- package/dist/ssr/client.js +0 -2
- package/dist/ssr/client.js.map +1 -1
- package/dist/ssr/server.d.ts +2 -1
- package/dist/ssr/server.d.ts.map +1 -1
- package/dist/ssr/server.js +19 -16
- package/dist/ssr/server.js.map +1 -1
- package/dist/types.d.ts +0 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/types.dom.d.ts +3 -3
- package/dist/types.dom.d.ts.map +1 -1
- package/dist/utils/format.d.ts +1 -2
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/format.js +1 -4
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/runtime.d.ts +3 -2
- package/dist/utils/runtime.d.ts.map +1 -1
- package/dist/utils/runtime.js +5 -2
- package/dist/utils/runtime.js.map +1 -1
- package/dist/utils/vdom.d.ts.map +1 -1
- package/dist/utils/vdom.js +2 -2
- package/dist/utils/vdom.js.map +1 -1
- package/package.json +4 -8
- package/src/components/memo.ts +3 -11
- package/src/context.ts +1 -24
- package/src/dom.ts +145 -96
- package/src/error.ts +2 -4
- package/src/form/index.ts +6 -9
- package/src/globals.ts +1 -1
- package/src/hmr.ts +14 -5
- package/src/hooks/useEffectEvent.ts +0 -1
- package/src/hooks/usePromise.ts +0 -1
- package/src/hooks/utils.ts +12 -12
- package/src/hydration.ts +21 -57
- package/src/reconciler.ts +2 -6
- package/src/recursiveRender.ts +10 -9
- package/src/renderToString.ts +0 -1
- package/src/router/client/index.ts +14 -100
- package/src/router/context.ts +6 -7
- package/src/router/fileRouter.ts +2 -6
- package/src/router/fileRouterController.ts +39 -159
- package/src/router/globals.ts +0 -4
- package/src/router/head.ts +7 -5
- package/src/router/index.ts +1 -12
- package/src/router/link.ts +3 -3
- package/src/router/{ssg → server}/index.ts +10 -17
- package/src/router/types.internal.ts +0 -5
- package/src/router/types.ts +4 -48
- package/src/router/utils/index.ts +16 -79
- package/src/scheduler.ts +83 -70
- package/src/signals/base.ts +0 -8
- package/src/signals/computed.ts +30 -18
- package/src/signals/for.ts +15 -10
- package/src/signals/utils.ts +2 -1
- package/src/signals/watch.ts +27 -22
- package/src/ssr/client.ts +1 -4
- package/src/ssr/server.ts +21 -20
- package/src/types.dom.ts +4 -5
- package/src/types.ts +0 -10
- package/src/utils/format.ts +0 -5
- package/src/utils/runtime.ts +6 -2
- package/src/utils/vdom.ts +2 -7
- package/dist/router/guard.d.ts +0 -17
- package/dist/router/guard.d.ts.map +0 -1
- package/dist/router/guard.js +0 -45
- package/dist/router/guard.js.map +0 -1
- package/dist/router/ssg/index.d.ts.map +0 -1
- package/dist/router/ssg/index.js.map +0 -1
- package/dist/router/ssr/index.d.ts +0 -20
- package/dist/router/ssr/index.d.ts.map +0 -1
- package/dist/router/ssr/index.js +0 -160
- package/dist/router/ssr/index.js.map +0 -1
- package/src/router/guard.ts +0 -72
- package/src/router/ssr/index.ts +0 -247
|
@@ -1,27 +1,19 @@
|
|
|
1
1
|
import { createElement } from "../../element.js"
|
|
2
2
|
import { __DEV__ } from "../../env.js"
|
|
3
|
-
import { resolveNavguard } from "../guard.js"
|
|
4
3
|
import type {
|
|
5
|
-
DefaultComponentModule,
|
|
6
4
|
FormattedViteImportMap,
|
|
7
|
-
GuardModule,
|
|
8
5
|
RouteMatch,
|
|
9
6
|
ViteImportMap,
|
|
10
7
|
} from "../types.internal"
|
|
11
|
-
import { OnBeforeEnterHook, OnBeforeLeaveHook } from "../types.js"
|
|
12
8
|
|
|
13
9
|
export {
|
|
14
10
|
formatViteImportMap,
|
|
15
11
|
matchRoute,
|
|
16
12
|
match404Route,
|
|
17
|
-
|
|
13
|
+
matchLayouts,
|
|
18
14
|
normalizePrefixPath,
|
|
19
15
|
parseQuery,
|
|
20
16
|
wrapWithLayouts,
|
|
21
|
-
runBeforeLeaveHooks,
|
|
22
|
-
runBeforeEnterHooks,
|
|
23
|
-
runBeforeEachGuards,
|
|
24
|
-
runAfterEachGuards,
|
|
25
17
|
}
|
|
26
18
|
|
|
27
19
|
function formatViteImportMap(
|
|
@@ -41,7 +33,7 @@ function formatViteImportMap(
|
|
|
41
33
|
}
|
|
42
34
|
|
|
43
35
|
let specificity = 0
|
|
44
|
-
let k = key.slice(dirIndex + dir.length)
|
|
36
|
+
let k = baseUrl + key.slice(dirIndex + dir.length)
|
|
45
37
|
while (k.startsWith("/")) {
|
|
46
38
|
k = k.slice(1)
|
|
47
39
|
}
|
|
@@ -95,7 +87,7 @@ function formatViteImportMap(
|
|
|
95
87
|
|
|
96
88
|
return {
|
|
97
89
|
...acc,
|
|
98
|
-
[
|
|
90
|
+
[segments.join("/")]: value,
|
|
99
91
|
}
|
|
100
92
|
}, {})
|
|
101
93
|
}
|
|
@@ -185,20 +177,23 @@ function match404Route(
|
|
|
185
177
|
return null
|
|
186
178
|
}
|
|
187
179
|
|
|
188
|
-
function
|
|
189
|
-
|
|
180
|
+
function matchLayouts(
|
|
181
|
+
layouts: FormattedViteImportMap,
|
|
190
182
|
routeSegments: string[]
|
|
191
183
|
) {
|
|
192
|
-
return ["/", ...routeSegments].reduce(
|
|
193
|
-
|
|
194
|
-
|
|
184
|
+
return ["/", ...routeSegments].reduce(
|
|
185
|
+
(acc, _, i) => {
|
|
186
|
+
const layoutPath = routeSegments.slice(0, i).join("/")
|
|
187
|
+
const layout = layouts[layoutPath]
|
|
195
188
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
189
|
+
if (!layout) {
|
|
190
|
+
return acc
|
|
191
|
+
}
|
|
199
192
|
|
|
200
|
-
|
|
201
|
-
|
|
193
|
+
return [...acc, layout]
|
|
194
|
+
},
|
|
195
|
+
[] as FormattedViteImportMap[string][]
|
|
196
|
+
)
|
|
202
197
|
}
|
|
203
198
|
|
|
204
199
|
function normalizePrefixPath(path: string) {
|
|
@@ -247,61 +242,3 @@ function wrapWithLayouts(
|
|
|
247
242
|
createElement(page, props)
|
|
248
243
|
)
|
|
249
244
|
}
|
|
250
|
-
|
|
251
|
-
function runBeforeLeaveHooks(
|
|
252
|
-
hooks: OnBeforeLeaveHook[],
|
|
253
|
-
context: Kiru.RequestContext,
|
|
254
|
-
to: string,
|
|
255
|
-
from: string = to
|
|
256
|
-
): false | void {
|
|
257
|
-
for (const hook of hooks) {
|
|
258
|
-
const res = hook(context, to, from)
|
|
259
|
-
if (res === false) {
|
|
260
|
-
return false
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
async function runBeforeEnterHooks(
|
|
266
|
-
hooks: OnBeforeEnterHook[],
|
|
267
|
-
context: Kiru.RequestContext,
|
|
268
|
-
to: string,
|
|
269
|
-
from: string = to
|
|
270
|
-
) {
|
|
271
|
-
for (const hook of hooks) {
|
|
272
|
-
const result = await hook(context, to, from)
|
|
273
|
-
if (typeof result === "string") {
|
|
274
|
-
return result
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return null
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
async function runBeforeEachGuards(
|
|
282
|
-
guardModules: GuardModule[],
|
|
283
|
-
context: Kiru.RequestContext,
|
|
284
|
-
to: string,
|
|
285
|
-
from: string = to
|
|
286
|
-
): Promise<string | null> {
|
|
287
|
-
const beforeHooks = guardModules
|
|
288
|
-
.map((guardModule) => resolveNavguard(guardModule)?.beforeEach)
|
|
289
|
-
.filter((x) => typeof x === "function")
|
|
290
|
-
|
|
291
|
-
return runBeforeEnterHooks(beforeHooks, context, to, from)
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
async function runAfterEachGuards(
|
|
295
|
-
guardModules: GuardModule[],
|
|
296
|
-
context: Kiru.RequestContext,
|
|
297
|
-
to: string,
|
|
298
|
-
from: string = to
|
|
299
|
-
): Promise<void> {
|
|
300
|
-
const afterHooks = guardModules
|
|
301
|
-
.map((guardModule) => resolveNavguard(guardModule)?.afterEach)
|
|
302
|
-
.filter((x) => typeof x === "function")
|
|
303
|
-
|
|
304
|
-
for (const hook of afterHooks) {
|
|
305
|
-
await hook(context, to, from)
|
|
306
|
-
}
|
|
307
|
-
}
|
package/src/scheduler.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
import {
|
|
8
8
|
$CONTEXT_PROVIDER,
|
|
9
9
|
$ERROR_BOUNDARY,
|
|
10
|
+
$MEMO,
|
|
10
11
|
CONSECUTIVE_DIRTY_LIMIT,
|
|
11
12
|
FLAG_DELETION,
|
|
12
13
|
FLAG_DIRTY,
|
|
@@ -33,8 +34,11 @@ import {
|
|
|
33
34
|
isExoticType,
|
|
34
35
|
getVNodeAppContext,
|
|
35
36
|
findParentErrorBoundary,
|
|
37
|
+
call,
|
|
36
38
|
} from "./utils/index.js"
|
|
37
39
|
import type { AppContext } from "./appContext"
|
|
40
|
+
import type { MemoFn } from "./components/memo"
|
|
41
|
+
import { isHmrUpdate } from "./hmr.js"
|
|
38
42
|
|
|
39
43
|
type VNode = Kiru.VNode
|
|
40
44
|
|
|
@@ -55,7 +59,7 @@ let animationFrameHandle = -1
|
|
|
55
59
|
* Runs a function after any existing work has been completed,
|
|
56
60
|
* or immediately if the scheduler is already idle.
|
|
57
61
|
*/
|
|
58
|
-
export function nextIdle(fn: () => void) {
|
|
62
|
+
export function nextIdle(fn: () => void): void {
|
|
59
63
|
if (isRunningOrQueued) {
|
|
60
64
|
nextIdleEffects.push(fn)
|
|
61
65
|
return
|
|
@@ -66,13 +70,13 @@ export function nextIdle(fn: () => void) {
|
|
|
66
70
|
/**
|
|
67
71
|
* Syncronously flushes any pending work.
|
|
68
72
|
*/
|
|
69
|
-
export function flushSync() {
|
|
73
|
+
export function flushSync(): void {
|
|
70
74
|
if (!isRunningOrQueued) return
|
|
71
75
|
window.cancelAnimationFrame(animationFrameHandle)
|
|
72
76
|
doWork()
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
export function renderRootSync(rootNode: VNode) {
|
|
79
|
+
export function renderRootSync(rootNode: VNode): void {
|
|
76
80
|
rootNode.flags |= FLAG_DIRTY
|
|
77
81
|
treesInProgress.push(rootNode)
|
|
78
82
|
|
|
@@ -90,20 +94,20 @@ export function requestUpdate(vNode: VNode): void {
|
|
|
90
94
|
queueUpdate(vNode)
|
|
91
95
|
}
|
|
92
96
|
|
|
93
|
-
function queueBeginWork() {
|
|
97
|
+
function queueBeginWork(): void {
|
|
94
98
|
if (isRunningOrQueued) return
|
|
95
99
|
isRunningOrQueued = true
|
|
96
100
|
animationFrameHandle = window.requestAnimationFrame(doWork)
|
|
97
101
|
}
|
|
98
102
|
|
|
99
|
-
function onWorkFinished() {
|
|
103
|
+
function onWorkFinished(): void {
|
|
100
104
|
isRunningOrQueued = false
|
|
101
105
|
while (nextIdleEffects.length) {
|
|
102
106
|
nextIdleEffects.shift()!()
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
109
|
|
|
106
|
-
function queueUpdate(vNode: VNode) {
|
|
110
|
+
function queueUpdate(vNode: VNode): void {
|
|
107
111
|
// In immediate effect mode (useLayoutEffect), immediately mark the render as dirty
|
|
108
112
|
if (isImmediateEffectsMode) {
|
|
109
113
|
immediateEffectDirtiedRender = true
|
|
@@ -129,12 +133,12 @@ function queueUpdate(vNode: VNode) {
|
|
|
129
133
|
treesInProgress.push(vNode)
|
|
130
134
|
}
|
|
131
135
|
|
|
132
|
-
function queueDelete(vNode: VNode) {
|
|
136
|
+
function queueDelete(vNode: VNode): void {
|
|
133
137
|
traverseApply(vNode, (n) => (n.flags |= FLAG_DELETION))
|
|
134
138
|
deletions.push(vNode)
|
|
135
139
|
}
|
|
136
140
|
|
|
137
|
-
const depthSort = (a: VNode, b: VNode) => b.depth - a.depth
|
|
141
|
+
const depthSort = (a: VNode, b: VNode): number => b.depth - a.depth
|
|
138
142
|
|
|
139
143
|
let currentWorkRoot: VNode | null = null
|
|
140
144
|
|
|
@@ -163,7 +167,7 @@ function doWork(): void {
|
|
|
163
167
|
const flags = currentWorkRoot.flags
|
|
164
168
|
if (flags & FLAG_DELETION) continue
|
|
165
169
|
if (flags & FLAG_DIRTY) {
|
|
166
|
-
let n: VNode |
|
|
170
|
+
let n: VNode | null = currentWorkRoot
|
|
167
171
|
while ((n = performUnitOfWork(n))) {}
|
|
168
172
|
|
|
169
173
|
while (deletions.length) {
|
|
@@ -194,7 +198,7 @@ function doWork(): void {
|
|
|
194
198
|
consecutiveDirtyCount = 0
|
|
195
199
|
|
|
196
200
|
onWorkFinished()
|
|
197
|
-
flushEffects(postEffects)
|
|
201
|
+
queueMicrotask(() => flushEffects(postEffects))
|
|
198
202
|
if (__DEV__) {
|
|
199
203
|
window.__kiru.emit("update", appCtx!)
|
|
200
204
|
window.__kiru.profilingContext?.emit("update", appCtx!)
|
|
@@ -202,15 +206,57 @@ function doWork(): void {
|
|
|
202
206
|
}
|
|
203
207
|
}
|
|
204
208
|
|
|
205
|
-
function performUnitOfWork(vNode: VNode): VNode |
|
|
206
|
-
|
|
209
|
+
function performUnitOfWork(vNode: VNode): VNode | null {
|
|
210
|
+
const next = updateVNode(vNode)
|
|
211
|
+
|
|
212
|
+
if (vNode.deletions !== null) {
|
|
213
|
+
vNode.deletions.forEach(queueDelete)
|
|
214
|
+
vNode.deletions = null
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (next) {
|
|
218
|
+
return next
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
let nextNode: VNode | null = vNode
|
|
222
|
+
while (nextNode) {
|
|
223
|
+
// queue effects upon ascent
|
|
224
|
+
if (nextNode.immediateEffects) {
|
|
225
|
+
preEffects.push(...nextNode.immediateEffects)
|
|
226
|
+
nextNode.immediateEffects = undefined
|
|
227
|
+
}
|
|
228
|
+
if (nextNode.effects) {
|
|
229
|
+
postEffects.push(...nextNode.effects)
|
|
230
|
+
nextNode.effects = undefined
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (nextNode === currentWorkRoot) return null
|
|
234
|
+
if (nextNode.sibling) {
|
|
235
|
+
return nextNode.sibling
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
nextNode = nextNode.parent
|
|
239
|
+
if (renderMode.current === "hydrate" && nextNode?.dom) {
|
|
240
|
+
hydrationStack.pop()
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return null
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function updateVNode(vNode: VNode): VNode | null {
|
|
248
|
+
const { type, props, prev, flags } = vNode
|
|
249
|
+
if (__DEV__ && isHmrUpdate()) {
|
|
250
|
+
} else if ((flags & FLAG_DIRTY) === 0 && props === prev?.props) {
|
|
251
|
+
return null
|
|
252
|
+
}
|
|
207
253
|
try {
|
|
208
|
-
if (typeof
|
|
209
|
-
updateHostComponent(vNode as DomVNode)
|
|
210
|
-
} else if (isExoticType(
|
|
211
|
-
updateExoticComponent(vNode)
|
|
254
|
+
if (typeof type === "string") {
|
|
255
|
+
return updateHostComponent(vNode as DomVNode)
|
|
256
|
+
} else if (isExoticType(type)) {
|
|
257
|
+
return updateExoticComponent(vNode)
|
|
212
258
|
} else {
|
|
213
|
-
|
|
259
|
+
return updateFunctionComponent(vNode as FunctionVNode)
|
|
214
260
|
}
|
|
215
261
|
} catch (error) {
|
|
216
262
|
if (__DEV__) {
|
|
@@ -243,47 +289,16 @@ function performUnitOfWork(vNode: VNode): VNode | void {
|
|
|
243
289
|
throw error
|
|
244
290
|
}
|
|
245
291
|
console.error(error)
|
|
246
|
-
return
|
|
292
|
+
return vNode.child
|
|
247
293
|
}
|
|
248
294
|
setTimeout(() => {
|
|
249
295
|
throw error
|
|
250
296
|
})
|
|
251
297
|
}
|
|
252
|
-
|
|
253
|
-
if (vNode.deletions !== null) {
|
|
254
|
-
vNode.deletions.forEach(queueDelete)
|
|
255
|
-
vNode.deletions = null
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
if (renderChild && vNode.child) {
|
|
259
|
-
return vNode.child
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
let nextNode: VNode | null = vNode
|
|
263
|
-
while (nextNode) {
|
|
264
|
-
// queue effects upon ascent
|
|
265
|
-
if (nextNode.immediateEffects) {
|
|
266
|
-
preEffects.push(...nextNode.immediateEffects)
|
|
267
|
-
nextNode.immediateEffects = undefined
|
|
268
|
-
}
|
|
269
|
-
if (nextNode.effects) {
|
|
270
|
-
postEffects.push(...nextNode.effects)
|
|
271
|
-
nextNode.effects = undefined
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
if (nextNode === currentWorkRoot) return
|
|
275
|
-
if (nextNode.sibling) {
|
|
276
|
-
return nextNode.sibling
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
nextNode = nextNode.parent
|
|
280
|
-
if (renderMode.current === "hydrate" && nextNode?.dom) {
|
|
281
|
-
hydrationStack.pop()
|
|
282
|
-
}
|
|
283
|
-
}
|
|
298
|
+
return null
|
|
284
299
|
}
|
|
285
300
|
|
|
286
|
-
function updateExoticComponent(vNode: VNode) {
|
|
301
|
+
function updateExoticComponent(vNode: VNode): VNode | null {
|
|
287
302
|
const { props, type } = vNode
|
|
288
303
|
let children = props.children
|
|
289
304
|
|
|
@@ -309,20 +324,19 @@ function updateExoticComponent(vNode: VNode) {
|
|
|
309
324
|
}
|
|
310
325
|
}
|
|
311
326
|
|
|
312
|
-
vNode.child = reconcileChildren(vNode, children)
|
|
327
|
+
return (vNode.child = reconcileChildren(vNode, children))
|
|
313
328
|
}
|
|
314
329
|
|
|
315
|
-
function updateFunctionComponent(vNode: FunctionVNode) {
|
|
330
|
+
function updateFunctionComponent(vNode: FunctionVNode): VNode | null {
|
|
316
331
|
const { type, props, subs, prev, flags } = vNode
|
|
317
332
|
if (flags & FLAG_MEMO) {
|
|
318
|
-
vNode.memoizedProps = props
|
|
319
333
|
if (
|
|
320
|
-
prev
|
|
321
|
-
|
|
322
|
-
!
|
|
334
|
+
prev &&
|
|
335
|
+
(type as MemoFn)[$MEMO](prev.props, props) &&
|
|
336
|
+
!(__DEV__ && isHmrUpdate())
|
|
323
337
|
) {
|
|
324
338
|
vNode.flags |= FLAG_NOOP
|
|
325
|
-
return
|
|
339
|
+
return null
|
|
326
340
|
}
|
|
327
341
|
vNode.flags &= ~FLAG_NOOP
|
|
328
342
|
}
|
|
@@ -345,14 +359,14 @@ function updateFunctionComponent(vNode: FunctionVNode) {
|
|
|
345
359
|
* and not clearing the entire set.
|
|
346
360
|
*/
|
|
347
361
|
if (subs) {
|
|
348
|
-
subs.forEach(
|
|
362
|
+
subs.forEach(call)
|
|
349
363
|
subs.clear()
|
|
350
364
|
}
|
|
351
365
|
|
|
352
366
|
if (__DEV__) {
|
|
353
367
|
newChild = latest(type)(props)
|
|
354
368
|
|
|
355
|
-
if (
|
|
369
|
+
if (isHmrUpdate() && vNode.hooks && vNode.hookSig) {
|
|
356
370
|
const len = vNode.hooks.length
|
|
357
371
|
if (hookIndex.current < len) {
|
|
358
372
|
// clean up any hooks that were removed
|
|
@@ -365,7 +379,6 @@ function updateFunctionComponent(vNode: FunctionVNode) {
|
|
|
365
379
|
}
|
|
366
380
|
}
|
|
367
381
|
|
|
368
|
-
delete vNode.hmrUpdated
|
|
369
382
|
if (++renderTryCount > CONSECUTIVE_DIRTY_LIMIT) {
|
|
370
383
|
throw new KiruError({
|
|
371
384
|
message:
|
|
@@ -378,14 +391,14 @@ function updateFunctionComponent(vNode: FunctionVNode) {
|
|
|
378
391
|
}
|
|
379
392
|
newChild = type(props)
|
|
380
393
|
} while (isRenderDirtied)
|
|
381
|
-
|
|
382
|
-
return
|
|
394
|
+
|
|
395
|
+
return (vNode.child = reconcileChildren(vNode, newChild))
|
|
383
396
|
} finally {
|
|
384
397
|
node.current = null
|
|
385
398
|
}
|
|
386
399
|
}
|
|
387
400
|
|
|
388
|
-
function updateHostComponent(vNode: DomVNode) {
|
|
401
|
+
function updateHostComponent(vNode: DomVNode): VNode | null {
|
|
389
402
|
const { props, type } = vNode
|
|
390
403
|
if (__DEV__) {
|
|
391
404
|
assertValidElementProps(vNode)
|
|
@@ -396,10 +409,8 @@ function updateHostComponent(vNode: DomVNode) {
|
|
|
396
409
|
} else {
|
|
397
410
|
vNode.dom = createDom(vNode)
|
|
398
411
|
}
|
|
399
|
-
if (__DEV__) {
|
|
400
|
-
|
|
401
|
-
vNode.dom.__kiruNode = vNode
|
|
402
|
-
}
|
|
412
|
+
if (__DEV__ && vNode.dom instanceof Element) {
|
|
413
|
+
vNode.dom.__kiruNode = vNode
|
|
403
414
|
}
|
|
404
415
|
}
|
|
405
416
|
// text should _never_ have children
|
|
@@ -409,9 +420,11 @@ function updateHostComponent(vNode: DomVNode) {
|
|
|
409
420
|
hydrationStack.push(vNode.dom!)
|
|
410
421
|
}
|
|
411
422
|
}
|
|
423
|
+
|
|
424
|
+
return vNode.child
|
|
412
425
|
}
|
|
413
426
|
|
|
414
|
-
function checkForTooManyConsecutiveDirtyRenders() {
|
|
427
|
+
function checkForTooManyConsecutiveDirtyRenders(): void {
|
|
415
428
|
if (consecutiveDirtyCount > CONSECUTIVE_DIRTY_LIMIT) {
|
|
416
429
|
throw new KiruError(
|
|
417
430
|
"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."
|
|
@@ -419,7 +432,7 @@ function checkForTooManyConsecutiveDirtyRenders() {
|
|
|
419
432
|
}
|
|
420
433
|
}
|
|
421
434
|
|
|
422
|
-
function flushEffects(effectArr: Function[]) {
|
|
435
|
+
function flushEffects(effectArr: Function[]): void {
|
|
423
436
|
for (let i = 0; i < effectArr.length; i++) {
|
|
424
437
|
effectArr[i]()
|
|
425
438
|
}
|
package/src/signals/base.ts
CHANGED
|
@@ -17,7 +17,6 @@ export class Signal<T> {
|
|
|
17
17
|
[$SIGNAL] = true;
|
|
18
18
|
[$HMR_ACCEPT]?: HMRAccept<Signal<any>>
|
|
19
19
|
displayName?: string
|
|
20
|
-
private onBeforeRead?: () => void
|
|
21
20
|
protected $subs?: Set<SignalSubscriber<any>>
|
|
22
21
|
protected $id: string
|
|
23
22
|
protected $value: T
|
|
@@ -60,7 +59,6 @@ export class Signal<T> {
|
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
get value() {
|
|
63
|
-
this.onBeforeRead?.()
|
|
64
62
|
if (__DEV__) {
|
|
65
63
|
const tgt = latest(this)
|
|
66
64
|
Signal.entangle(tgt)
|
|
@@ -86,7 +84,6 @@ export class Signal<T> {
|
|
|
86
84
|
}
|
|
87
85
|
|
|
88
86
|
peek() {
|
|
89
|
-
this.onBeforeRead?.()
|
|
90
87
|
if (__DEV__) {
|
|
91
88
|
return latest(this).$value
|
|
92
89
|
}
|
|
@@ -105,7 +102,6 @@ export class Signal<T> {
|
|
|
105
102
|
}
|
|
106
103
|
|
|
107
104
|
toString() {
|
|
108
|
-
this.onBeforeRead?.()
|
|
109
105
|
if (__DEV__) {
|
|
110
106
|
const tgt = latest(this)
|
|
111
107
|
Signal.entangle(tgt)
|
|
@@ -192,10 +188,6 @@ export class Signal<T> {
|
|
|
192
188
|
;(vNode.subs ??= new Set()).add(unsub)
|
|
193
189
|
}
|
|
194
190
|
|
|
195
|
-
static configure(signal: Signal<any>, onBeforeRead?: () => void) {
|
|
196
|
-
signal.onBeforeRead = onBeforeRead
|
|
197
|
-
}
|
|
198
|
-
|
|
199
191
|
static dispose(signal: Signal<any>) {
|
|
200
192
|
signal.$isDisposed = true
|
|
201
193
|
if (__DEV__) {
|
package/src/signals/computed.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __DEV__ } from "../env.js"
|
|
2
2
|
import { $HMR_ACCEPT } from "../constants.js"
|
|
3
3
|
import { depsRequireChange, useHook } from "../hooks/utils.js"
|
|
4
|
-
import { latest } from "../utils/index.js"
|
|
4
|
+
import { call, latest } from "../utils/index.js"
|
|
5
5
|
import { effectQueue, signalSubsMap } from "./globals.js"
|
|
6
6
|
import { executeWithTracking } from "./effect.js"
|
|
7
7
|
import { Signal } from "./base.js"
|
|
@@ -32,28 +32,23 @@ export class ComputedSignal<T> extends Signal<T> {
|
|
|
32
32
|
destroy: () => {},
|
|
33
33
|
} satisfies HMRAccept<ComputedSignal<T>>
|
|
34
34
|
}
|
|
35
|
-
Signal.configure(this, () => {
|
|
36
|
-
if (!this.$isDirty) return
|
|
37
|
-
if (__DEV__) {
|
|
38
|
-
/**
|
|
39
|
-
* This is a safeguard for dev-mode only, where a 'read' on an
|
|
40
|
-
* already-disposed signal during HMR update => `dom.setSignalProp`
|
|
41
|
-
* would throw due to invalid subs-map access.
|
|
42
|
-
*
|
|
43
|
-
* Perhaps in future we could handle this better by carrying over
|
|
44
|
-
* the previous signal's ID and not disposing it / deleting the
|
|
45
|
-
* map entry.
|
|
46
|
-
*/
|
|
47
|
-
if (this.$isDisposed) return
|
|
48
|
-
}
|
|
49
|
-
ComputedSignal.run(this)
|
|
50
|
-
})
|
|
51
35
|
}
|
|
52
36
|
|
|
53
37
|
get value() {
|
|
38
|
+
this.ensureNotDirty()
|
|
54
39
|
return super.value
|
|
55
40
|
}
|
|
56
41
|
|
|
42
|
+
toString() {
|
|
43
|
+
this.ensureNotDirty()
|
|
44
|
+
return super.toString()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
peek() {
|
|
48
|
+
this.ensureNotDirty()
|
|
49
|
+
return super.peek()
|
|
50
|
+
}
|
|
51
|
+
|
|
57
52
|
// @ts-expect-error
|
|
58
53
|
set value(next: T) {}
|
|
59
54
|
|
|
@@ -83,7 +78,7 @@ export class ComputedSignal<T> extends Signal<T> {
|
|
|
83
78
|
const { $id, $unsubs } = latest(computed)
|
|
84
79
|
|
|
85
80
|
effectQueue.delete($id)
|
|
86
|
-
$unsubs.forEach(
|
|
81
|
+
$unsubs.forEach(call)
|
|
87
82
|
$unsubs.clear()
|
|
88
83
|
computed.$isDirty = true
|
|
89
84
|
}
|
|
@@ -111,6 +106,23 @@ export class ComputedSignal<T> extends Signal<T> {
|
|
|
111
106
|
$computed.sneak(value)
|
|
112
107
|
$computed.$isDirty = false
|
|
113
108
|
}
|
|
109
|
+
|
|
110
|
+
private ensureNotDirty() {
|
|
111
|
+
if (!this.$isDirty) return
|
|
112
|
+
if (__DEV__) {
|
|
113
|
+
/**
|
|
114
|
+
* This is a safeguard for dev-mode only, where a 'read' on an
|
|
115
|
+
* already-disposed signal during HMR update => `dom.setSignalProp`
|
|
116
|
+
* would throw due to invalid subs-map access.
|
|
117
|
+
*
|
|
118
|
+
* Perhaps in future we could handle this better by carrying over
|
|
119
|
+
* the previous signal's ID and not disposing it / deleting the
|
|
120
|
+
* map entry.
|
|
121
|
+
*/
|
|
122
|
+
if (this.$isDisposed) return
|
|
123
|
+
}
|
|
124
|
+
ComputedSignal.run(this)
|
|
125
|
+
}
|
|
114
126
|
}
|
|
115
127
|
|
|
116
128
|
export function computed<T>(
|
package/src/signals/for.ts
CHANGED
|
@@ -1,25 +1,30 @@
|
|
|
1
1
|
import type { Signal } from "./base.js"
|
|
2
|
+
import { unwrap } from "./utils.js"
|
|
2
3
|
|
|
3
|
-
type InferArraySignalItemType<T extends Signal<any[]
|
|
4
|
-
infer V
|
|
5
|
-
>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
:
|
|
9
|
-
|
|
4
|
+
type InferArraySignalItemType<T extends Signal<any[]> | readonly unknown[]> =
|
|
5
|
+
T extends Signal<infer V>
|
|
6
|
+
? V extends Array<infer W>
|
|
7
|
+
? W
|
|
8
|
+
: never
|
|
9
|
+
: T extends unknown[]
|
|
10
|
+
? T[number]
|
|
11
|
+
: never
|
|
10
12
|
|
|
11
|
-
type ForProps<
|
|
13
|
+
type ForProps<
|
|
14
|
+
T extends Signal<any[]> | readonly unknown[],
|
|
15
|
+
U = InferArraySignalItemType<T>,
|
|
16
|
+
> = {
|
|
12
17
|
each: T
|
|
13
18
|
fallback?: JSX.Element
|
|
14
19
|
children: (value: U, index: number, array: U[]) => JSX.Element
|
|
15
20
|
}
|
|
16
21
|
|
|
17
|
-
export function For<T extends Signal<any[]
|
|
22
|
+
export function For<T extends Signal<any[]> | unknown[]>({
|
|
18
23
|
each,
|
|
19
24
|
fallback,
|
|
20
25
|
children,
|
|
21
26
|
}: ForProps<T>) {
|
|
22
|
-
const items = each
|
|
27
|
+
const items = unwrap(each, true)
|
|
23
28
|
if (items.length === 0) return fallback
|
|
24
29
|
return items.map(children)
|
|
25
30
|
}
|
package/src/signals/utils.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { call } from "../utils/index.js"
|
|
1
2
|
import { Signal } from "./base.js"
|
|
2
3
|
import { effectQueue } from "./globals.js"
|
|
3
4
|
|
|
@@ -7,6 +8,6 @@ export function unwrap<T>(value: T | Signal<T>, reactive = false): T {
|
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export const tick = () => {
|
|
10
|
-
effectQueue.forEach(
|
|
11
|
+
effectQueue.forEach(call)
|
|
11
12
|
effectQueue.clear()
|
|
12
13
|
}
|