kiru 0.46.1 → 0.47.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.
Files changed (62) hide show
  1. package/dist/appContext.d.ts +6 -17
  2. package/dist/appContext.d.ts.map +1 -1
  3. package/dist/appContext.js +39 -95
  4. package/dist/appContext.js.map +1 -1
  5. package/dist/constants.d.ts +2 -1
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +2 -1
  8. package/dist/constants.js.map +1 -1
  9. package/dist/context.d.ts.map +1 -1
  10. package/dist/context.js +0 -2
  11. package/dist/context.js.map +1 -1
  12. package/dist/dom.d.ts.map +1 -1
  13. package/dist/dom.js +10 -13
  14. package/dist/dom.js.map +1 -1
  15. package/dist/hmr.d.ts +1 -2
  16. package/dist/hmr.d.ts.map +1 -1
  17. package/dist/hmr.js +0 -2
  18. package/dist/hmr.js.map +1 -1
  19. package/dist/index.d.ts +0 -3
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +0 -20
  22. package/dist/index.js.map +1 -1
  23. package/dist/portal.d.ts +2 -5
  24. package/dist/portal.d.ts.map +1 -1
  25. package/dist/portal.js +22 -22
  26. package/dist/portal.js.map +1 -1
  27. package/dist/profiling.d.ts +1 -1
  28. package/dist/renderToString.d.ts +1 -1
  29. package/dist/renderToString.d.ts.map +1 -1
  30. package/dist/renderToString.js +3 -6
  31. package/dist/renderToString.js.map +1 -1
  32. package/dist/scheduler.d.ts +3 -3
  33. package/dist/scheduler.d.ts.map +1 -1
  34. package/dist/scheduler.js +52 -68
  35. package/dist/scheduler.js.map +1 -1
  36. package/dist/ssr/client.d.ts +1 -2
  37. package/dist/ssr/client.d.ts.map +1 -1
  38. package/dist/ssr/client.js +6 -4
  39. package/dist/ssr/client.js.map +1 -1
  40. package/dist/ssr/server.d.ts +1 -1
  41. package/dist/ssr/server.d.ts.map +1 -1
  42. package/dist/ssr/server.js +24 -27
  43. package/dist/ssr/server.js.map +1 -1
  44. package/dist/swr.d.ts +1 -1
  45. package/dist/swr.d.ts.map +1 -1
  46. package/dist/swr.js +1 -1
  47. package/dist/swr.js.map +1 -1
  48. package/dist/utils.js +1 -1
  49. package/package.json +1 -1
  50. package/src/appContext.ts +50 -117
  51. package/src/constants.ts +2 -0
  52. package/src/context.ts +0 -1
  53. package/src/dom.ts +10 -10
  54. package/src/hmr.ts +1 -3
  55. package/src/index.ts +0 -40
  56. package/src/portal.ts +22 -26
  57. package/src/renderToString.ts +3 -9
  58. package/src/scheduler.ts +51 -70
  59. package/src/ssr/client.ts +13 -19
  60. package/src/ssr/server.ts +25 -35
  61. package/src/swr.ts +1 -1
  62. package/src/utils.ts +1 -1
package/src/scheduler.ts CHANGED
@@ -31,7 +31,7 @@ let appCtx: AppContext | null
31
31
  let nextUnitOfWork: VNode | null = null
32
32
  let treesInProgress: VNode[] = []
33
33
  let currentTreeIndex = 0
34
- let isRunning = false
34
+ let isRunningOrQueued = false
35
35
  let nextIdleEffects: (() => void)[] = []
36
36
  let deletions: VNode[] = []
37
37
  let isImmediateEffectsMode = false
@@ -41,20 +41,27 @@ let consecutiveDirtyCount = 0
41
41
  let pendingContextChanges = new Set<ContextProviderNode<any>>()
42
42
  let preEffects: Array<Function> = []
43
43
  let postEffects: Array<Function> = []
44
+ let animationFrameHandle = -1
44
45
 
45
46
  /**
46
- * Runs a function after any existing work has been completed, or if the scheduler is already idle.
47
+ * Runs a function after any existing work has been completed,
48
+ * or immediately if the scheduler is already idle.
47
49
  */
48
- export function nextIdle(fn: () => void, wakeUpIfIdle = true) {
49
- nextIdleEffects.push(fn)
50
- if (wakeUpIfIdle) wake()
50
+ export function nextIdle(fn: () => void) {
51
+ if (isRunningOrQueued) {
52
+ nextIdleEffects.push(fn)
53
+ return
54
+ }
55
+ fn()
51
56
  }
52
57
 
53
58
  /**
54
59
  * Syncronously flushes any pending work.
55
60
  */
56
61
  export function flushSync() {
57
- workLoop()
62
+ if (!isRunningOrQueued) return
63
+ window.cancelAnimationFrame(animationFrameHandle)
64
+ doWork()
58
65
  }
59
66
 
60
67
  /**
@@ -65,33 +72,22 @@ export function requestUpdate(vNode: VNode): void {
65
72
  if (renderMode.current === "hydrate") {
66
73
  return nextIdle(() => {
67
74
  vNode.flags & FLAG_DELETION || queueUpdate(vNode)
68
- }, false)
75
+ })
69
76
  }
70
77
  queueUpdate(vNode)
71
78
  }
72
79
 
73
- export function requestDelete(vNode: VNode): void {
74
- if (vNode.flags & FLAG_DELETION) return
75
- if (renderMode.current === "hydrate") {
76
- return nextIdle(() => {
77
- vNode.flags & FLAG_DELETION || queueDelete(vNode)
78
- }, false)
79
- }
80
- queueDelete(vNode)
81
- }
82
-
83
- function queueWorkLoop() {
84
- queueMicrotask(workLoop)
85
- }
86
-
87
- function wake() {
88
- if (isRunning) return
89
- isRunning = true
90
- queueWorkLoop()
80
+ function queueBeginWork() {
81
+ if (isRunningOrQueued) return
82
+ isRunningOrQueued = true
83
+ animationFrameHandle = window.requestAnimationFrame(doWork)
91
84
  }
92
85
 
93
- function sleep() {
94
- isRunning = false
86
+ function onWorkFinished() {
87
+ isRunningOrQueued = false
88
+ while (nextIdleEffects.length) {
89
+ nextIdleEffects.shift()!()
90
+ }
95
91
  }
96
92
 
97
93
  function queueUpdate(vNode: VNode) {
@@ -117,7 +113,7 @@ function queueUpdate(vNode: VNode) {
117
113
  if (nextUnitOfWork === null) {
118
114
  treesInProgress.push(vNode)
119
115
  nextUnitOfWork = vNode
120
- return wake()
116
+ return queueBeginWork()
121
117
  }
122
118
 
123
119
  for (let i = 0; i < treesInProgress.length; i++) {
@@ -202,7 +198,7 @@ function queueDelete(vNode: VNode) {
202
198
  deletions.push(vNode)
203
199
  }
204
200
 
205
- function workLoop(): void {
201
+ function doWork(): void {
206
202
  if (__DEV__) {
207
203
  const n = nextUnitOfWork ?? deletions[0] ?? treesInProgress[0]
208
204
  if (n) {
@@ -220,55 +216,40 @@ function workLoop(): void {
220
216
  queueBlockedContextDependencyRoots()
221
217
  }
222
218
 
223
- if (!nextUnitOfWork && (deletions.length || treesInProgress.length)) {
224
- while (deletions.length) {
225
- commitDeletion(deletions.shift()!)
226
- }
227
- const workRoots = [...treesInProgress]
228
- treesInProgress.length = 0
229
- currentTreeIndex = 0
230
- for (const root of workRoots) {
231
- commitWork(root)
232
- }
233
-
234
- isImmediateEffectsMode = true
235
- flushEffects(preEffects)
236
- isImmediateEffectsMode = false
219
+ while (deletions.length) {
220
+ commitDeletion(deletions.shift()!)
221
+ }
222
+ const workRoots = [...treesInProgress]
223
+ treesInProgress.length = 0
224
+ currentTreeIndex = 0
225
+ for (const root of workRoots) {
226
+ commitWork(root)
227
+ }
237
228
 
238
- if (immediateEffectDirtiedRender) {
239
- checkForTooManyConsecutiveDirtyRenders()
240
- flushEffects(postEffects)
241
- immediateEffectDirtiedRender = false
242
- consecutiveDirtyCount++
243
- if (__DEV__) {
244
- window.__kiru?.profilingContext?.endTick(appCtx!)
245
- window.__kiru?.profilingContext?.emit("updateDirtied", appCtx!)
246
- }
247
- return flushSync()
248
- }
249
- consecutiveDirtyCount = 0
229
+ isImmediateEffectsMode = true
230
+ flushEffects(preEffects)
231
+ isImmediateEffectsMode = false
250
232
 
233
+ if (immediateEffectDirtiedRender) {
234
+ checkForTooManyConsecutiveDirtyRenders()
251
235
  flushEffects(postEffects)
236
+ immediateEffectDirtiedRender = false
237
+ consecutiveDirtyCount++
252
238
  if (__DEV__) {
253
- window.__kiru!.emit("update", appCtx!)
254
- window.__kiru?.profilingContext?.emit("update", appCtx!)
239
+ window.__kiru?.profilingContext?.endTick(appCtx!)
240
+ window.__kiru?.profilingContext?.emit("updateDirtied", appCtx!)
255
241
  }
242
+ return flushSync()
256
243
  }
244
+ consecutiveDirtyCount = 0
257
245
 
258
- if (!nextUnitOfWork) {
259
- sleep()
260
- while (nextIdleEffects.length) {
261
- nextIdleEffects.shift()!()
262
- }
263
- if (__DEV__) {
264
- if (appCtx) {
265
- window.__kiru?.profilingContext?.endTick(appCtx)
266
- }
267
- }
268
- return
246
+ onWorkFinished()
247
+ flushEffects(postEffects)
248
+ if (__DEV__) {
249
+ window.__kiru!.emit("update", appCtx!)
250
+ window.__kiru?.profilingContext?.emit("update", appCtx!)
251
+ window.__kiru?.profilingContext?.endTick(appCtx!)
269
252
  }
270
-
271
- queueWorkLoop()
272
253
  }
273
254
 
274
255
  function queueBlockedContextDependencyRoots(): VNode | null {
package/src/ssr/client.ts CHANGED
@@ -3,27 +3,21 @@ import { hydrationStack } from "../hydration.js"
3
3
  import { renderMode } from "../globals.js"
4
4
  import { mount } from "../index.js"
5
5
 
6
- export function hydrate<T extends Record<string, unknown>>(
7
- appFunc: (props: T) => JSX.Element,
8
- container: AppContextOptions,
9
- appProps?: T
10
- ): Promise<AppContext<T>>
11
-
12
- export function hydrate<T extends Record<string, unknown>>(
13
- appFunc: (props: T) => JSX.Element,
6
+ export function hydrate(
7
+ children: JSX.Element,
14
8
  container: HTMLElement,
15
- appProps?: T
16
- ): Promise<AppContext<T>>
17
-
18
- export function hydrate<T extends Record<string, unknown>>(
19
- appFunc: (props: T) => JSX.Element,
20
- optionsOrRoot: HTMLElement | AppContextOptions,
21
- appProps = {} as T
22
- ) {
9
+ options?: AppContextOptions
10
+ ): AppContext {
23
11
  hydrationStack.clear()
12
+
24
13
  const prevRenderMode = renderMode.current
25
14
  renderMode.current = "hydrate"
26
- return mount(appFunc, optionsOrRoot as any, appProps).finally(() => {
27
- renderMode.current = prevRenderMode
28
- })
15
+ hydrationStack.captureEvents(container)
16
+
17
+ const app = mount(children, container, options)
18
+
19
+ renderMode.current = prevRenderMode
20
+ hydrationStack.releaseEvents(container)
21
+
22
+ return app
29
23
  }
package/src/ssr/server.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { Readable } from "node:stream"
2
2
  import { Fragment } from "../element.js"
3
- import { AppContext, createAppContext } from "../appContext.js"
4
3
  import { renderMode, node } from "../globals.js"
5
4
  import {
6
5
  isVNode,
@@ -8,36 +7,27 @@ import {
8
7
  propsToElementAttributes,
9
8
  isExoticType,
10
9
  } from "../utils.js"
11
- import { Signal } from "../signals/base.js"
10
+ import { Signal } from "../signals/index.js"
12
11
  import { $HYDRATION_BOUNDARY, voidElements } from "../constants.js"
13
12
  import { assertValidElementProps } from "../props.js"
14
13
  import { HYDRATION_BOUNDARY_MARKER } from "./hydrationBoundary.js"
15
14
  import { __DEV__ } from "../env.js"
16
15
 
17
- type RequestState = {
18
- stream: Readable
19
- ctx: AppContext
20
- }
21
-
22
- export function renderToReadableStream<T extends Record<string, unknown>>(
23
- appFunc: (props: T) => JSX.Element,
24
- appProps = {} as T
25
- ): Readable {
16
+ export function renderToReadableStream(element: JSX.Element): Readable {
26
17
  const prev = renderMode.current
27
18
  renderMode.current = "stream"
28
- const state: RequestState = {
29
- stream: new Readable(),
30
- ctx: createAppContext(appFunc, appProps, { rootType: Fragment }),
31
- }
32
- renderToStream_internal(state, state.ctx.rootNode, null, 0)
33
- state.stream.push(null)
19
+ const stream = new Readable()
20
+ const rootNode = Fragment({ children: element })
21
+
22
+ renderToStream_internal(stream, rootNode, null, 0)
23
+ stream.push(null)
34
24
  renderMode.current = prev
35
25
 
36
- return state.stream
26
+ return stream
37
27
  }
38
28
 
39
29
  function renderToStream_internal(
40
- state: RequestState,
30
+ stream: Readable,
41
31
  el: unknown,
42
32
  parent: Kiru.VNode | null,
43
33
  idx: number
@@ -46,23 +36,23 @@ function renderToStream_internal(
46
36
  if (el === undefined) return
47
37
  if (typeof el === "boolean") return
48
38
  if (typeof el === "string") {
49
- state.stream.push(encodeHtmlEntities(el))
39
+ stream.push(encodeHtmlEntities(el))
50
40
  return
51
41
  }
52
42
  if (typeof el === "number" || typeof el === "bigint") {
53
- state.stream.push(el.toString())
43
+ stream.push(el.toString())
54
44
  return
55
45
  }
56
46
  if (el instanceof Array) {
57
- el.forEach((c, i) => renderToStream_internal(state, c, parent, i))
47
+ el.forEach((c, i) => renderToStream_internal(stream, c, parent, i))
58
48
  return
59
49
  }
60
50
  if (Signal.isSignal(el)) {
61
- state.stream.push(String(el.peek()))
51
+ stream.push(String(el.peek()))
62
52
  return
63
53
  }
64
54
  if (!isVNode(el)) {
65
- state.stream.push(String(el))
55
+ stream.push(String(el))
66
56
  return
67
57
  }
68
58
  el.parent = parent
@@ -72,35 +62,35 @@ function renderToStream_internal(
72
62
  const children = props.children
73
63
  const type = el.type
74
64
  if (type === "#text") {
75
- state.stream.push(encodeHtmlEntities(props.nodeValue ?? ""))
65
+ stream.push(encodeHtmlEntities(props.nodeValue ?? ""))
76
66
  return
77
67
  }
78
68
  if (isExoticType(type)) {
79
69
  if (type === $HYDRATION_BOUNDARY) {
80
- state.stream.push(`<!--${HYDRATION_BOUNDARY_MARKER}-->`)
81
- renderToStream_internal(state, children, el, idx)
82
- state.stream.push(`<!--/${HYDRATION_BOUNDARY_MARKER}-->`)
70
+ stream.push(`<!--${HYDRATION_BOUNDARY_MARKER}-->`)
71
+ renderToStream_internal(stream, children, el, idx)
72
+ stream.push(`<!--/${HYDRATION_BOUNDARY_MARKER}-->`)
83
73
  return
84
74
  }
85
- return renderToStream_internal(state, children, el, idx)
75
+ return renderToStream_internal(stream, children, el, idx)
86
76
  }
87
77
 
88
78
  if (typeof type !== "string") {
89
79
  node.current = el
90
80
  const res = type(props)
91
81
  node.current = null
92
- return renderToStream_internal(state, res, parent, idx)
82
+ return renderToStream_internal(stream, res, parent, idx)
93
83
  }
94
84
 
95
85
  if (__DEV__) {
96
86
  assertValidElementProps(el)
97
87
  }
98
88
  const attrs = propsToElementAttributes(props)
99
- state.stream.push(`<${type}${attrs.length ? ` ${attrs}` : ""}>`)
89
+ stream.push(`<${type}${attrs.length ? ` ${attrs}` : ""}>`)
100
90
 
101
91
  if (!voidElements.has(type)) {
102
92
  if ("innerHTML" in props) {
103
- state.stream.push(
93
+ stream.push(
104
94
  String(
105
95
  Signal.isSignal(props.innerHTML)
106
96
  ? props.innerHTML.peek()
@@ -109,12 +99,12 @@ function renderToStream_internal(
109
99
  )
110
100
  } else {
111
101
  if (Array.isArray(children)) {
112
- children.forEach((c, i) => renderToStream_internal(state, c, el, i))
102
+ children.forEach((c, i) => renderToStream_internal(stream, c, el, i))
113
103
  } else {
114
- renderToStream_internal(state, children, el, 0)
104
+ renderToStream_internal(stream, children, el, 0)
115
105
  }
116
106
  }
117
107
 
118
- state.stream.push(`</${type}>`)
108
+ stream.push(`</${type}>`)
119
109
  }
120
110
  }
package/src/swr.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { __DEV__ } from "./env.js"
2
2
  import { useHook } from "./hooks/utils.js"
3
- import { Signal } from "./signals/base.js"
3
+ import { Signal } from "./signals/index.js"
4
4
  import {
5
5
  noop,
6
6
  deepCompare,
package/src/utils.ts CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  FLAG_UPDATE,
11
11
  REGEX_UNIT,
12
12
  } from "./constants.js"
13
- import { unwrap } from "./signals/utils.js"
13
+ import { unwrap } from "./signals/index.js"
14
14
  import { __DEV__ } from "./env.js"
15
15
  import type { AppContext } from "./appContext"
16
16