kiru 0.54.0-preview.0 → 0.54.0-preview.1
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/derive.d.ts +1 -1
- package/dist/components/derive.d.ts.map +1 -1
- package/dist/components/derive.js +3 -2
- package/dist/components/derive.js.map +1 -1
- package/dist/dom.d.ts.map +1 -1
- package/dist/dom.js +6 -2
- package/dist/dom.js.map +1 -1
- package/dist/hooks/usePromise.d.ts +2 -1
- package/dist/hooks/usePromise.d.ts.map +1 -1
- package/dist/hooks/usePromise.js +31 -62
- package/dist/hooks/usePromise.js.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/router/client/index.d.ts.map +1 -1
- package/dist/router/client/index.js +12 -4
- package/dist/router/client/index.js.map +1 -1
- package/dist/router/constants.d.ts +2 -0
- package/dist/router/constants.d.ts.map +1 -0
- package/dist/router/constants.js +2 -0
- package/dist/router/constants.js.map +1 -0
- package/dist/router/fileRouterController.d.ts.map +1 -1
- package/dist/router/fileRouterController.js +123 -106
- package/dist/router/fileRouterController.js.map +1 -1
- package/dist/router/ssg/index.js +1 -1
- package/dist/router/ssg/index.js.map +1 -1
- package/dist/router/ssr/index.d.ts.map +1 -1
- package/dist/router/ssr/index.js +29 -26
- package/dist/router/ssr/index.js.map +1 -1
- package/dist/router/types.d.ts +5 -12
- package/dist/router/types.d.ts.map +1 -1
- package/dist/scheduler.d.ts +14 -3
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +3 -4
- package/dist/scheduler.js.map +1 -1
- package/dist/ssr/server.d.ts +8 -1
- package/dist/ssr/server.d.ts.map +1 -1
- package/dist/ssr/server.js +28 -18
- package/dist/ssr/server.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/promise.d.ts +2 -0
- package/dist/utils/promise.d.ts.map +1 -1
- package/dist/utils/promise.js +45 -1
- package/dist/utils/promise.js.map +1 -1
- package/package.json +1 -1
- package/src/components/derive.ts +5 -3
- package/src/dom.ts +5 -1
- package/src/hooks/usePromise.ts +57 -77
- package/src/index.ts +1 -1
- package/src/router/client/index.ts +16 -4
- package/src/router/constants.ts +1 -0
- package/src/router/fileRouterController.ts +180 -137
- package/src/router/ssg/index.ts +1 -1
- package/src/router/ssr/index.ts +38 -33
- package/src/router/types.ts +5 -12
- package/src/scheduler.ts +20 -3
- package/src/ssr/server.ts +48 -22
- package/src/utils/index.ts +1 -1
- package/src/utils/promise.ts +70 -1
package/src/scheduler.ts
CHANGED
|
@@ -52,10 +52,27 @@ let postEffects: Array<Function> = []
|
|
|
52
52
|
let animationFrameHandle = -1
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
55
|
+
* Defers work until the scheduler becomes idle.
|
|
56
|
+
*
|
|
57
|
+
* This works in two modes:
|
|
58
|
+
* - `await nextIdle()` resolves once idle, allowing async/await usage.
|
|
59
|
+
* - `nextIdle(fn)` schedules a callback to run when idle.
|
|
60
|
+
*
|
|
61
|
+
* Callbacks are executed before promises resolve,
|
|
62
|
+
* and multiple calls queue until the scheduler becomes idle.
|
|
57
63
|
*/
|
|
58
|
-
export function nextIdle(
|
|
64
|
+
export function nextIdle(): Promise<void>
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Schedules `fn` to run once the scheduler becomes idle.
|
|
68
|
+
* If already idle, `fn` executes immediately.
|
|
69
|
+
*/
|
|
70
|
+
export function nextIdle<T extends () => void>(fn: T): void
|
|
71
|
+
|
|
72
|
+
export function nextIdle(fn?: () => void): void | Promise<void> {
|
|
73
|
+
if (!fn) {
|
|
74
|
+
return new Promise<void>(nextIdle)
|
|
75
|
+
}
|
|
59
76
|
if (isRunningOrQueued) {
|
|
60
77
|
nextIdleEffects.push(fn)
|
|
61
78
|
return
|
package/src/ssr/server.ts
CHANGED
|
@@ -20,33 +20,29 @@ d.currentScript.remove()
|
|
|
20
20
|
</script>
|
|
21
21
|
`.replace(/\s+/g, " ")
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
interface RenderToReadableStreamConfig {
|
|
24
|
+
/**
|
|
25
|
+
* Include additional data to stream - must be resolved on the client manually.
|
|
26
|
+
*/
|
|
27
|
+
data?: Kiru.StatefulPromise<unknown>[]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function renderToReadableStream(
|
|
31
|
+
element: JSX.Element,
|
|
32
|
+
config: RenderToReadableStreamConfig = {}
|
|
33
|
+
): {
|
|
24
34
|
immediate: string
|
|
25
35
|
stream: ReadableStream | null
|
|
26
36
|
} {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
const streamData = createStreamDataHandler()
|
|
38
|
+
if (config.data) {
|
|
39
|
+
streamData.enqueue(config.data)
|
|
40
|
+
}
|
|
30
41
|
|
|
31
42
|
let immediate = ""
|
|
32
|
-
|
|
33
43
|
const ctx: HeadlessRenderContext = {
|
|
34
44
|
write: (chunk) => (immediate += chunk),
|
|
35
|
-
onStreamData
|
|
36
|
-
for (const promise of data) {
|
|
37
|
-
if (streamPromises.has(promise)) continue
|
|
38
|
-
streamPromises.add(promise)
|
|
39
|
-
|
|
40
|
-
const dataPromise = promise
|
|
41
|
-
.then(() => ({ data: promise.value }))
|
|
42
|
-
.catch(() => ({ error: promise.error?.message }))
|
|
43
|
-
.then(
|
|
44
|
-
(value, content = JSON.stringify(value)) =>
|
|
45
|
-
`<script id="${promise.id}" k-data type="application/json">${content}</script>`
|
|
46
|
-
)
|
|
47
|
-
dataPromises.push(dataPromise)
|
|
48
|
-
}
|
|
49
|
-
},
|
|
45
|
+
onStreamData: streamData.enqueue,
|
|
50
46
|
}
|
|
51
47
|
|
|
52
48
|
const prev = renderMode.current
|
|
@@ -54,10 +50,11 @@ export function renderToReadableStream(element: JSX.Element): {
|
|
|
54
50
|
headlessRender(ctx, Fragment({ children: element }), null, 0)
|
|
55
51
|
renderMode.current = prev
|
|
56
52
|
|
|
57
|
-
|
|
53
|
+
let stream: ReadableStream | null = null
|
|
54
|
+
if (streamData.chunks.length > 0) {
|
|
58
55
|
stream = new ReadableStream({
|
|
59
56
|
async pull(controller) {
|
|
60
|
-
for await (const chunk of
|
|
57
|
+
for await (const chunk of streamData.chunks) {
|
|
61
58
|
controller.enqueue(chunk)
|
|
62
59
|
}
|
|
63
60
|
controller.enqueue(STREAMED_DATA_SETUP)
|
|
@@ -68,3 +65,32 @@ export function renderToReadableStream(element: JSX.Element): {
|
|
|
68
65
|
|
|
69
66
|
return { immediate, stream }
|
|
70
67
|
}
|
|
68
|
+
|
|
69
|
+
interface StreamDataHandler {
|
|
70
|
+
enqueue: NonNullable<HeadlessRenderContext["onStreamData"]>
|
|
71
|
+
chunks: Promise<string>[]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function createStreamDataHandler(): StreamDataHandler {
|
|
75
|
+
const seen = new Set<Kiru.StatefulPromise<unknown>>()
|
|
76
|
+
const chunks: Promise<string>[] = []
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
chunks,
|
|
80
|
+
enqueue: (items) => {
|
|
81
|
+
for (const item of items) {
|
|
82
|
+
if (seen.has(item)) continue
|
|
83
|
+
seen.add(item)
|
|
84
|
+
|
|
85
|
+
const chunk = item
|
|
86
|
+
.then(() => ({ data: item.value }))
|
|
87
|
+
.catch(() => ({ error: item.error?.message }))
|
|
88
|
+
.then(
|
|
89
|
+
(value, content = JSON.stringify(value)) =>
|
|
90
|
+
`<script id="${item.id}" k-data type="application/json">${content}</script>`
|
|
91
|
+
)
|
|
92
|
+
chunks.push(chunk)
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
}
|
package/src/utils/index.ts
CHANGED
package/src/utils/promise.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $STREAM_DATA } from "../constants.js"
|
|
1
|
+
import { $STREAM_DATA, STREAMED_DATA_EVENT } from "../constants.js"
|
|
2
2
|
|
|
3
3
|
export interface StreamDataThrowValue {
|
|
4
4
|
[$STREAM_DATA]: {
|
|
@@ -24,3 +24,72 @@ export function isStatefulPromise(
|
|
|
24
24
|
): thing is Kiru.StatefulPromise<unknown> {
|
|
25
25
|
return thing instanceof Promise && "id" in thing && "state" in thing
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
export function createStatefulPromise<T, U extends Record<string, unknown>>(
|
|
29
|
+
id: string,
|
|
30
|
+
promise: Promise<T>,
|
|
31
|
+
extra: U = {} as U,
|
|
32
|
+
_finally: null | (() => void) = null
|
|
33
|
+
): Kiru.StatefulPromise<T> & U {
|
|
34
|
+
const state: Kiru.PromiseState<T> = { id, state: "pending" }
|
|
35
|
+
const p = Object.assign(promise, state, extra)
|
|
36
|
+
p.then(
|
|
37
|
+
(value) => {
|
|
38
|
+
p.state = "fulfilled"
|
|
39
|
+
p.value = value
|
|
40
|
+
},
|
|
41
|
+
(error) => {
|
|
42
|
+
p.state = "rejected"
|
|
43
|
+
p.error = error instanceof Error ? error : new Error(String(error))
|
|
44
|
+
}
|
|
45
|
+
).finally(_finally)
|
|
46
|
+
|
|
47
|
+
return p
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface StreamedPromiseEventDetail<T> {
|
|
51
|
+
id: string
|
|
52
|
+
data?: T
|
|
53
|
+
error?: string
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function resolveStreamedPromise<T>(
|
|
57
|
+
id: string,
|
|
58
|
+
signal?: AbortSignal
|
|
59
|
+
): Promise<T> {
|
|
60
|
+
const deferralCache: Map<string, { data?: T; error?: string }> = // @ts-ignore
|
|
61
|
+
(window[STREAMED_DATA_EVENT] ??= new Map())
|
|
62
|
+
|
|
63
|
+
const existing = deferralCache.get(id)
|
|
64
|
+
if (existing) {
|
|
65
|
+
deferralCache.delete(id)
|
|
66
|
+
|
|
67
|
+
const { data, error } = existing
|
|
68
|
+
if (error) {
|
|
69
|
+
return Promise.reject(error)
|
|
70
|
+
}
|
|
71
|
+
return Promise.resolve(data!)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return new Promise<T>((resolve, reject) => {
|
|
75
|
+
const onDataEvent = (event: Event) => {
|
|
76
|
+
const { detail } = event as CustomEvent<StreamedPromiseEventDetail<T>>
|
|
77
|
+
if (detail.id === id) {
|
|
78
|
+
deferralCache.delete(id)
|
|
79
|
+
window.removeEventListener(STREAMED_DATA_EVENT, onDataEvent)
|
|
80
|
+
|
|
81
|
+
const { data, error } = detail
|
|
82
|
+
if (error) {
|
|
83
|
+
return reject(error)
|
|
84
|
+
}
|
|
85
|
+
resolve(data!)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
window.addEventListener(STREAMED_DATA_EVENT, onDataEvent)
|
|
90
|
+
signal?.addEventListener("abort", () => {
|
|
91
|
+
window.removeEventListener(STREAMED_DATA_EVENT, onDataEvent)
|
|
92
|
+
reject("aborted")
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
}
|