@tanstack/redact 0.0.21 → 0.1.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/core/attributes.js +2 -1
- package/dist/core/attributes.js.map +2 -2
- package/dist/core/browser.d.ts +9 -0
- package/dist/core/browser.js +35 -0
- package/dist/core/browser.js.map +7 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +3 -3
- package/dist/core/internal.d.ts +31 -8
- package/dist/core/internal.js +3 -1
- package/dist/core/internal.js.map +2 -2
- package/dist/core/resource-hints.d.ts +7 -0
- package/dist/core/resource-hints.js +19 -0
- package/dist/core/resource-hints.js.map +7 -0
- package/dist/core/types.js +1 -1
- package/dist/dom/_all.d.ts +11 -16
- package/dist/dom/_all.js +9 -20
- package/dist/dom/_all.js.map +2 -2
- package/dist/dom/client.d.ts +4 -4
- package/dist/dom/client.js +4 -4
- package/dist/dom/commit.d.ts +23 -0
- package/dist/dom/commit.js +191 -0
- package/dist/dom/commit.js.map +7 -0
- package/dist/dom/dispatcher.d.ts +4 -22
- package/dist/dom/dispatcher.js +184 -126
- package/dist/dom/dispatcher.js.map +3 -3
- package/dist/dom/dom.d.ts +2 -0
- package/dist/dom/dom.js +72 -52
- package/dist/dom/dom.js.map +2 -2
- package/dist/dom/error-info.d.ts +2 -0
- package/dist/dom/error-info.js +16 -0
- package/dist/dom/error-info.js.map +7 -0
- package/dist/dom/event-replay.js +1 -1
- package/dist/dom/features/activity/full.d.ts +1 -0
- package/dist/dom/features/activity/full.js +162 -0
- package/dist/dom/features/activity/full.js.map +7 -0
- package/dist/dom/features/activity/index.d.ts +1 -0
- package/dist/dom/features/activity/index.js +3 -0
- package/dist/dom/features/activity/index.js.map +7 -0
- package/dist/dom/features/activity/stub.d.ts +1 -0
- package/dist/dom/features/activity/stub.js +12 -0
- package/dist/dom/features/activity/stub.js.map +7 -0
- package/dist/dom/features/class/full.js +87 -27
- package/dist/dom/features/class/full.js.map +2 -2
- package/dist/dom/features/class/index.d.ts +1 -1
- package/dist/dom/features/class/index.js +2 -2
- package/dist/dom/features/class/stub.js +3 -3
- package/dist/dom/features/context/full.d.ts +4 -1
- package/dist/dom/features/context/full.js +72 -15
- package/dist/dom/features/context/full.js.map +2 -2
- package/dist/dom/features/context/index.d.ts +1 -1
- package/dist/dom/features/context/index.js +2 -2
- package/dist/dom/features/context/stub.d.ts +4 -1
- package/dist/dom/features/context/stub.js +17 -8
- package/dist/dom/features/context/stub.js.map +2 -2
- package/dist/dom/features/forward-ref/full.js +12 -21
- package/dist/dom/features/forward-ref/full.js.map +2 -2
- package/dist/dom/features/forward-ref/index.d.ts +1 -1
- package/dist/dom/features/forward-ref/index.js +2 -2
- package/dist/dom/features/forward-ref/stub.js +4 -4
- package/dist/dom/features/fragment-refs/index.d.ts +1 -0
- package/dist/dom/features/fragment-refs/index.js +8 -0
- package/dist/dom/features/fragment-refs/index.js.map +7 -0
- package/dist/dom/features/fragment-refs/stub.d.ts +3 -0
- package/dist/dom/features/fragment-refs/stub.js +14 -0
- package/dist/dom/features/fragment-refs/stub.js.map +7 -0
- package/dist/dom/features/hydration/full.d.ts +11 -6
- package/dist/dom/features/hydration/full.js +76 -77
- package/dist/dom/features/hydration/full.js.map +2 -2
- package/dist/dom/features/hydration/index.d.ts +1 -1
- package/dist/dom/features/hydration/index.js +2 -2
- package/dist/dom/features/hydration/stub.d.ts +7 -2
- package/dist/dom/features/hydration/stub.js +1 -1
- package/dist/dom/features/hydration/stub.js.map +1 -1
- package/dist/dom/features/index.d.ts +8 -7
- package/dist/dom/features/index.js +9 -8
- package/dist/dom/features/index.js.map +2 -2
- package/dist/dom/features/lazy/full.js +4 -4
- package/dist/dom/features/lazy/index.d.ts +1 -1
- package/dist/dom/features/lazy/index.js +2 -2
- package/dist/dom/features/lazy/stub.js +4 -4
- package/dist/dom/features/memo/full.js +8 -6
- package/dist/dom/features/memo/full.js.map +2 -2
- package/dist/dom/features/memo/index.d.ts +1 -1
- package/dist/dom/features/memo/index.js +2 -2
- package/dist/dom/features/memo/stub.js +4 -4
- package/dist/dom/features/portal/full.js +4 -4
- package/dist/dom/features/portal/index.d.ts +1 -1
- package/dist/dom/features/portal/index.js +2 -2
- package/dist/dom/features/portal/stub.js +4 -4
- package/dist/dom/features/suspense/full.js +197 -52
- package/dist/dom/features/suspense/full.js.map +2 -2
- package/dist/dom/features/suspense/index.d.ts +1 -1
- package/dist/dom/features/suspense/index.js +2 -2
- package/dist/dom/features/suspense/stub.js +4 -4
- package/dist/dom/features/view-transition/full.d.ts +6 -0
- package/dist/dom/features/view-transition/full.js +280 -0
- package/dist/dom/features/view-transition/full.js.map +7 -0
- package/dist/dom/features/view-transition/index.d.ts +1 -0
- package/dist/dom/features/view-transition/index.js +3 -0
- package/dist/dom/features/view-transition/index.js.map +7 -0
- package/dist/dom/features/view-transition/resources.d.ts +11 -0
- package/dist/dom/features/view-transition/resources.js +108 -0
- package/dist/dom/features/view-transition/resources.js.map +7 -0
- package/dist/dom/features/view-transition/stub.d.ts +6 -0
- package/dist/dom/features/view-transition/stub.js +22 -0
- package/dist/dom/features/view-transition/stub.js.map +7 -0
- package/dist/dom/features/view-transition/visual.d.ts +14 -0
- package/dist/dom/features/view-transition/visual.js +356 -0
- package/dist/dom/features/view-transition/visual.js.map +7 -0
- package/dist/dom/fragment-instance.d.ts +40 -0
- package/dist/dom/fragment-instance.js +324 -0
- package/dist/dom/fragment-instance.js.map +7 -0
- package/dist/dom/index.d.ts +11 -11
- package/dist/dom/index.js +11 -18
- package/dist/dom/index.js.map +3 -3
- package/dist/dom/portal.d.ts +2 -2
- package/dist/dom/portal.js +2 -2
- package/dist/dom/portal.js.map +1 -1
- package/dist/dom/reconcile.d.ts +32 -3
- package/dist/dom/reconcile.js +689 -221
- package/dist/dom/reconcile.js.map +2 -2
- package/dist/dom/resource-hints.d.ts +6 -0
- package/dist/dom/resource-hints.js +115 -0
- package/dist/dom/resource-hints.js.map +7 -0
- package/dist/dom/resource-store.d.ts +13 -0
- package/dist/dom/resource-store.js +43 -0
- package/dist/dom/resource-store.js.map +7 -0
- package/dist/dom/resources.d.ts +1 -0
- package/dist/dom/resources.js +44 -0
- package/dist/dom/resources.js.map +7 -0
- package/dist/dom/retained-effects.d.ts +6 -0
- package/dist/dom/retained-effects.js +49 -0
- package/dist/dom/retained-effects.js.map +7 -0
- package/dist/dom/root-internal.d.ts +4 -4
- package/dist/dom/root-internal.js +2 -2
- package/dist/dom/root-internal.js.map +2 -2
- package/dist/dom/root.d.ts +5 -5
- package/dist/dom/root.js +11 -11
- package/dist/dom/root.js.map +2 -2
- package/dist/dom/test-utils.js +1 -1
- package/dist/react/activity.d.ts +7 -0
- package/dist/react/activity.js +8 -0
- package/dist/react/activity.js.map +7 -0
- package/dist/react/children.d.ts +1 -1
- package/dist/react/children.js +3 -3
- package/dist/react/children.js.map +1 -1
- package/dist/react/class.d.ts +1 -1
- package/dist/react/class.js +3 -3
- package/dist/react/class.js.map +1 -1
- package/dist/react/compiler-runtime.js +2 -2
- package/dist/react/context.d.ts +7 -2
- package/dist/react/context.js +3 -11
- package/dist/react/context.js.map +3 -3
- package/dist/react/element.d.ts +6 -3
- package/dist/react/element.js +7 -11
- package/dist/react/element.js.map +2 -2
- package/dist/react/hooks.d.ts +26 -7
- package/dist/react/hooks.js +13 -3
- package/dist/react/hooks.js.map +2 -2
- package/dist/react/index.d.ts +39 -24
- package/dist/react/index.js +39 -19
- package/dist/react/index.js.map +3 -3
- package/dist/react/jsx-runtime.d.ts +2 -2
- package/dist/react/jsx-runtime.js +3 -3
- package/dist/react/memo.d.ts +1 -1
- package/dist/react/memo.js +1 -1
- package/dist/react/portal.js +1 -1
- package/dist/react/shared-internals.d.ts +15 -5
- package/dist/react/shared-internals.js +2 -3
- package/dist/react/shared-internals.js.map +2 -2
- package/dist/react/suspense.js +1 -1
- package/dist/react/view-transition.d.ts +32 -0
- package/dist/react/view-transition.js +13 -0
- package/dist/react/view-transition.js.map +7 -0
- package/dist/scheduler/index.js +1 -1
- package/dist/server/bootstrap-script.d.ts +1 -23
- package/dist/server/bootstrap-script.js +7 -6
- package/dist/server/bootstrap-script.js.map +2 -2
- package/dist/server/dispatcher.d.ts +28 -6
- package/dist/server/dispatcher.js +33 -15
- package/dist/server/dispatcher.js.map +2 -2
- package/dist/server/escape.js +16 -15
- package/dist/server/escape.js.map +2 -2
- package/dist/server/index.d.ts +6 -6
- package/dist/server/index.js +7 -7
- package/dist/server/renderToString.d.ts +1 -1
- package/dist/server/renderToString.js +12 -8
- package/dist/server/renderToString.js.map +2 -2
- package/dist/server/resource-hints.d.ts +22 -0
- package/dist/server/resource-hints.js +148 -0
- package/dist/server/resource-hints.js.map +7 -0
- package/dist/server/stream.d.ts +15 -2
- package/dist/server/stream.js +155 -63
- package/dist/server/stream.js.map +2 -2
- package/dist/server/walk.d.ts +15 -2
- package/dist/server/walk.js +150 -110
- package/dist/server/walk.js.map +2 -2
- package/dist/vite/index.d.ts +6 -0
- package/dist/vite/index.js +22 -6
- package/dist/vite/index.js.map +2 -2
- package/package.json +1 -1
- package/src/core/attributes.ts +1 -0
- package/src/core/browser.ts +33 -0
- package/src/core/internal.ts +24 -6
- package/src/core/resource-hints.ts +36 -0
- package/src/dom/_all.ts +1 -7
- package/src/dom/commit.ts +186 -0
- package/src/dom/dispatcher.ts +190 -134
- package/src/dom/dom.ts +70 -54
- package/src/dom/error-info.ts +15 -0
- package/src/dom/features/activity/full.ts +166 -0
- package/src/dom/features/activity/index.ts +1 -0
- package/src/dom/features/activity/stub.ts +14 -0
- package/src/dom/features/class/full.ts +72 -28
- package/src/dom/features/context/full.ts +70 -13
- package/src/dom/features/context/stub.ts +10 -5
- package/src/dom/features/forward-ref/full.ts +9 -19
- package/src/dom/features/fragment-refs/index.ts +1 -0
- package/src/dom/features/fragment-refs/stub.ts +3 -0
- package/src/dom/features/hydration/full.ts +84 -85
- package/src/dom/features/hydration/stub.ts +1 -1
- package/src/dom/features/index.ts +1 -0
- package/src/dom/features/memo/full.ts +4 -3
- package/src/dom/features/suspense/full.ts +192 -55
- package/src/dom/features/view-transition/full.ts +288 -0
- package/src/dom/features/view-transition/index.ts +1 -0
- package/src/dom/features/view-transition/resources.ts +107 -0
- package/src/dom/features/view-transition/stub.ts +7 -0
- package/src/dom/features/view-transition/visual.ts +406 -0
- package/src/dom/fragment-instance.ts +337 -0
- package/src/dom/index.ts +6 -7
- package/src/dom/portal.ts +1 -1
- package/src/dom/reconcile.ts +695 -242
- package/src/dom/resource-hints.ts +115 -0
- package/src/dom/resource-store.ts +52 -0
- package/src/dom/resources.ts +39 -0
- package/src/dom/retained-effects.ts +38 -0
- package/src/dom/root-internal.ts +4 -4
- package/src/dom/root.ts +12 -14
- package/src/react/activity.ts +10 -0
- package/src/react/context.ts +4 -11
- package/src/react/element.ts +11 -12
- package/src/react/hooks.ts +12 -3
- package/src/react/index.ts +18 -0
- package/src/react/shared-internals.ts +3 -3
- package/src/react/view-transition.ts +41 -0
- package/src/server/bootstrap-script.ts +36 -5
- package/src/server/dispatcher.ts +35 -13
- package/src/server/escape.ts +15 -12
- package/src/server/renderToString.ts +7 -5
- package/src/server/resource-hints.ts +165 -0
- package/src/server/stream.ts +154 -62
- package/src/server/walk.ts +79 -26
- package/src/vite/index.ts +30 -13
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/server/stream.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ReactNode } from '../core'\nimport {\n beginSSR,\n endSSR,\n installSSRDispatcher,\n uninstallSSRDispatcher,\n applyContextSnapshot,\n} from './dispatcher'\nimport { walk, type SuspendedBoundary } from './walk'\nimport { BOUNDARY_REVEAL_RUNTIME, revealScript } from './bootstrap-script'\nimport { escapeScript } from './escape'\n\nexport interface StreamOptions {\n identifierPrefix?: string\n nonce?: string\n bootstrapScriptContent?: string | ReadonlyArray<string>\n bootstrapScripts?: ReadonlyArray<string | { src: string; async?: boolean; nonce?: string }>\n bootstrapModules?: ReadonlyArray<string | { src: string; nonce?: string }>\n onError?: (error: unknown) => string | void\n signal?: AbortSignal\n progressiveChunkSize?: number\n}\n\nexport interface ReadableStreamResult extends ReadableStream<Uint8Array> {\n allReady: Promise<void>\n}\n\nexport interface PipeableWritable {\n write(chunk: string): unknown\n end(): unknown\n}\n\nexport interface OrchestratorState {\n nextId: number\n pending: Set<Promise<void>>\n closed: boolean\n errored: unknown | null\n}\n\ntype Emit = (chunk: string) => void\n\nexport async function streamHtml(\n children: ReactNode,\n emit: Emit,\n options: StreamOptions,\n state: OrchestratorState,\n): Promise<void> {\n installSSRDispatcher()\n beginSSR(options.identifierPrefix)\n const nonce = options.nonce\n\n try {\n const boundaries: SuspendedBoundary[] = []\n\n // Buffer shell + bootstrap into a string[] and flush as a single emit.\n // Per-emit overhead in renderToReadableStream is TextEncoder.encode +\n // controller.enqueue \u2014 each walkHost normally fires 3+ emits (opening\n // tag, per-attribute, closing bracket), which for a ~30-component tree\n // is ~100 stream-controller round-trips. Batching collapses those into\n // one encode and one enqueue per shell \u2014 measured ~2-4% of total SSR\n // time on CPU profiles.\n const shellChunks: string[] = []\n const bufferedEmit: Emit = (chunk) => {\n shellChunks.push(chunk)\n }\n\n // 1. Render the shell. A root-level `use(promise)` has no Suspense\n // boundary to capture it, but App Router SSR commonly suspends at this\n // level while resolving the RSC stream. Wait and retry without leaking\n // partial shell chunks or boundary ids from the aborted attempt.\n let shellRendered = false\n let rootRetries = 0\n while (!shellRendered) {\n const chunkCount = shellChunks.length\n const boundaryCount = boundaries.length\n const nextId = state.nextId\n try {\n walk(children, {\n emit: bufferedEmit,\n onSuspend: (b) => boundaries.push(b),\n nextBoundaryId: () => state.nextId++,\n })\n shellRendered = true\n } catch (err) {\n shellChunks.length = chunkCount\n boundaries.length = boundaryCount\n state.nextId = nextId\n if (!isThenable(err)) throw err\n if (++rootRetries > 50) {\n throw new Error('renderToReadableStream exceeded 50 root suspension retries.')\n }\n await err\n }\n }\n\n // 2. Inject runtime + bootstrap scripts (once, after shell). Skip the\n // reveal/event-replay runtime when nothing needs it \u2014 no suspensions to\n // reveal and no bootstrap scripts to guard against early user input. That\n // keeps fully-static SSR responses byte-equivalent to a plain walk and\n // matches React's behavior where `renderToReadableStream` of a static\n // tree emits only the markup.\n const hasBootstrap =\n bootstrapScriptContentToArray(options.bootstrapScriptContent).length > 0 ||\n (options.bootstrapScripts?.length ?? 0) > 0 ||\n (options.bootstrapModules?.length ?? 0) > 0\n if (boundaries.length > 0 || hasBootstrap) {\n shellChunks.push(`<script${nonce ? ` nonce=\"${nonce}\"` : ''}>${BOUNDARY_REVEAL_RUNTIME}</script>`)\n for (const content of bootstrapScriptContentToArray(options.bootstrapScriptContent)) {\n shellChunks.push(inlineBootstrapTag(content, nonce))\n }\n for (const s of options.bootstrapScripts ?? []) {\n shellChunks.push(bootstrapTag(s, 'script', nonce))\n }\n for (const m of options.bootstrapModules ?? []) {\n shellChunks.push(bootstrapTag(m, 'module', nonce))\n }\n }\n\n if (shellChunks.length) emit(normalizeDocumentShell(shellChunks.join('')))\n\n // 3. Stream suspended boundaries as they resolve\n for (const b of boundaries) streamBoundary(b, emit, options, state)\n await drain(state)\n } catch (err) {\n state.errored = err\n if (options.onError) options.onError(err)\n throw err\n } finally {\n endSSR()\n uninstallSSRDispatcher()\n state.closed = true\n }\n}\n\nfunction streamBoundary(\n b: SuspendedBoundary,\n emit: Emit,\n options: StreamOptions,\n state: OrchestratorState,\n): void {\n const task = (async () => {\n try {\n await b.thenable\n } catch (err) {\n if (options.onError) options.onError(err)\n }\n if (state.closed) return\n\n // Re-render the boundary's children into a string, restoring the\n // provider stack from when the boundary first suspended.\n const parts: string[] = []\n const sub: SuspendedBoundary[] = []\n const restore = applyContextSnapshot(b.contextSnapshot)\n try {\n walk(b.children, {\n emit: (s) => parts.push(s),\n onSuspend: (n) => sub.push(n),\n nextBoundaryId: () => state.nextId++,\n })\n } catch (err) {\n if (options.onError) options.onError(err)\n restore()\n return\n }\n restore()\n\n emit(`<div hidden id=\"S:${b.id}\">${parts.join('')}</div>${revealScript(b.id, options.nonce)}`)\n\n // Recurse: any nested suspensions inside the now-revealed content\n for (const s of sub) streamBoundary(s, emit, options, state)\n })()\n state.pending.add(task)\n task.finally(() => state.pending.delete(task))\n}\n\nasync function drain(state: OrchestratorState): Promise<void> {\n while (state.pending.size > 0) {\n await Promise.race(state.pending)\n }\n}\n\nfunction isThenable(value: unknown): value is Promise<unknown> {\n return !!value && typeof (value as { then?: unknown }).then === 'function'\n}\n\nfunction bootstrapScriptContentToArray(\n content: StreamOptions['bootstrapScriptContent'],\n): string[] {\n if (content === undefined) return []\n return typeof content === 'string' ? [content] : [...content]\n}\n\nfunction inlineBootstrapTag(content: string, defaultNonce: string | undefined): string {\n const nAttr = defaultNonce ? ` nonce=\"${defaultNonce}\"` : ''\n return `<script${nAttr}>${escapeScript(content)}</script>`\n}\n\nfunction normalizeDocumentShell(html: string): string {\n const doctypeIndex = html.indexOf('<!DOCTYPE html><html')\n if (doctypeIndex <= 0) return html\n\n const headPrefix = html.slice(0, doctypeIndex)\n if (!isHeadPrefix(headPrefix)) return html\n\n const documentHtml = html.slice(doctypeIndex)\n const headOpen = documentHtml.match(/<head(?:\\s[^>]*)?>/)\n if (!headOpen || headOpen.index === undefined) return html\n\n const insertAt = headOpen.index + headOpen[0].length\n return documentHtml.slice(0, insertAt) + headPrefix + documentHtml.slice(insertAt)\n}\n\nfunction isHeadPrefix(value: string): boolean {\n if (!value) return false\n return stripLeadingHeadTags(value).trim() === ''\n}\n\nfunction stripLeadingHeadTags(value: string): string {\n let rest = value\n let changed = true\n while (changed) {\n changed = false\n const next = rest.replace(\n /^\\s*(?:<meta\\b[^>]*>|<link\\b[^>]*>|<base\\b[^>]*>|<title\\b[^>]*>[\\s\\S]*?<\\/title>|<style\\b[^>]*>[\\s\\S]*?<\\/style>|<script\\b[^>]*>[\\s\\S]*?<\\/script>)/i,\n '',\n )\n if (next !== rest) {\n rest = next\n changed = true\n }\n }\n return rest\n}\n\nfunction bootstrapTag(\n entry: string | { src: string; async?: boolean; nonce?: string },\n kind: 'script' | 'module',\n defaultNonce: string | undefined,\n): string {\n const src = typeof entry === 'string' ? entry : entry.src\n const nonce = typeof entry === 'string' ? defaultNonce : entry.nonce ?? defaultNonce\n const nAttr = nonce ? ` nonce=\"${nonce}\"` : ''\n if (kind === 'module') return `<script type=\"module\"${nAttr} src=\"${src}\"></script>`\n return `<script async${nAttr} src=\"${src}\"></script>`\n}\n\n// ---------------------------------------------------------------------------\n// Web Streams: renderToReadableStream\n// ---------------------------------------------------------------------------\n\nexport function renderToReadableStream(\n children: ReactNode,\n options: StreamOptions = {},\n): Promise<ReadableStreamResult> {\n const state: OrchestratorState = {\n nextId: 0,\n pending: new Set(),\n closed: false,\n errored: null,\n }\n const encoder = new TextEncoder()\n\n let allReadyResolve!: () => void\n let allReadyReject!: (e: unknown) => void\n const allReady = new Promise<void>((r, rej) => {\n allReadyResolve = r\n allReadyReject = rej\n })\n\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n const emit = (chunk: string) => {\n try {\n controller.enqueue(encoder.encode(chunk))\n } catch {}\n }\n\n streamHtml(children, emit, options, state).then(\n () => {\n try {\n controller.close()\n } catch {}\n allReadyResolve()\n },\n (err) => {\n try {\n controller.error(err)\n } catch {}\n allReadyReject(err)\n },\n )\n\n options.signal?.addEventListener('abort', () => {\n state.closed = true\n try {\n controller.close()\n } catch {}\n })\n },\n })\n\n return Promise.resolve(Object.assign(stream, { allReady }))\n}\n\n// ---------------------------------------------------------------------------\n// Node Streams: renderToPipeableStream\n// ---------------------------------------------------------------------------\n\nexport interface PipeableHandle {\n pipe<T extends PipeableWritable>(dest: T): T\n abort(reason?: unknown): void\n}\n\nexport interface PipeableOptions extends StreamOptions {\n onShellReady?: () => void\n onShellError?: (err: unknown) => void\n onAllReady?: () => void\n}\n\nexport function renderToPipeableStream(\n children: ReactNode,\n options: PipeableOptions = {},\n): PipeableHandle {\n const state: OrchestratorState = {\n nextId: 0,\n pending: new Set(),\n closed: false,\n errored: null,\n }\n\n const buffers: string[] = []\n let dest: PipeableWritable | null = null\n let shellReady = false\n let finished = false\n let aborted = false\n\n const flushTo = (w: PipeableWritable) => {\n if (!buffers.length) return\n for (const b of buffers) w.write(b)\n buffers.length = 0\n }\n\n const emit: Emit = (chunk) => {\n if (aborted || finished) return\n if (dest) dest.write(chunk)\n else buffers.push(chunk)\n }\n\n // Kick off rendering\n streamHtml(children, emit, options, state).then(\n () => {\n finished = true\n if (dest) dest.end()\n options.onAllReady?.()\n },\n (err) => {\n if (!shellReady) {\n options.onShellError?.(err)\n } else {\n options.onError?.(err)\n if (dest) dest.end()\n }\n },\n )\n\n // We call onShellReady once the first synchronous emit has landed.\n // streamHtml above runs the shell synchronously before the first await in drain(),\n // so we can schedule onShellReady right after the first microtask.\n queueMicrotask(() => {\n if (aborted || finished) return\n shellReady = true\n options.onShellReady?.()\n })\n\n return {\n pipe<T extends PipeableWritable>(target: T): T {\n dest = target\n flushTo(target)\n if (finished) target.end()\n return target\n },\n abort(_reason?: unknown) {\n aborted = true\n state.closed = true\n if (dest) dest.end()\n },\n }\n}\n"],
|
|
5
|
-
"mappings": ";AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,
|
|
4
|
+
"sourcesContent": ["import type { ReactNode } from '../core'\nimport {\n beginSSR,\n endSSR,\n applyContextSnapshot,\n currentSSRFrame,\n type SSRFrame,\n} from './dispatcher'\nimport { walk, type SuspendedBoundary, type BrowserBailoutCallback } from './walk'\nimport { browserError, isBrowserToken, isBrowserError } from '../core/browser'\nimport { BOUNDARY_REVEAL_RUNTIME, revealScript } from './bootstrap-script'\nimport { escapeAttr, escapeScript } from './escape'\nimport { resourceURL } from '../core/resource-hints'\nimport type { ResourceScope } from './resource-hints'\n\nexport interface StreamOptions {\n identifierPrefix?: string\n nonce?: string | { script?: string; style?: string }\n bootstrapScriptContent?: string | ReadonlyArray<string>\n bootstrapScripts?: ReadonlyArray<string | { src: string; async?: boolean; nonce?: string }>\n bootstrapModules?: ReadonlyArray<string | { src: string; nonce?: string }>\n onError?: (error: unknown) => string | void\n onBrowserBailout?: BrowserBailoutCallback\n signal?: AbortSignal\n progressiveChunkSize?: number\n}\n\nexport interface ReadableStreamResult extends ReadableStream<Uint8Array> {\n allReady: Promise<void>\n}\n\nexport interface PipeableWritable {\n write(chunk: string): unknown\n end(): unknown\n destroy?(error?: unknown): unknown\n}\n\nexport interface OrchestratorState {\n nextId: number\n pending: Set<Promise<void>>\n closed: boolean\n errored: unknown | null\n aborted: boolean\n reason: unknown\n abort: (reason?: unknown) => void\n cancelled: Promise<void>\n onShellReady?: () => void\n frame?: SSRFrame\n}\n\nfunction createState(): OrchestratorState {\n let wake!: () => void\n const state: OrchestratorState = {\n nextId: 0, pending: new Set(), closed: false, errored: null,\n aborted: false, reason: undefined,\n cancelled: new Promise<void>((resolve) => { wake = resolve }),\n abort(reason) {\n if (state.closed || state.aborted) return\n state.aborted = true\n state.reason = isBrowserToken(reason) ? browserError(reason) : reason ?? new Error('The render was aborted by the server without a reason.')\n wake()\n },\n }\n return state\n}\n\ntype Emit = (chunk: string) => void\n\nexport async function streamHtml(\n children: ReactNode,\n emit: Emit,\n options: StreamOptions,\n state: OrchestratorState,\n): Promise<void> {\n const nonce = scriptNonce(options)\n\n try {\n const boundaries: SuspendedBoundary[] = []\n\n // Buffer shell + bootstrap into a string[] and flush as a single emit.\n // Per-emit overhead in renderToReadableStream is TextEncoder.encode +\n // controller.enqueue \u2014 each walkHost normally fires 3+ emits (opening\n // tag, per-attribute, closing bracket), which for a ~30-component tree\n // is ~100 stream-controller round-trips. Batching collapses those into\n // one encode and one enqueue per shell \u2014 measured ~2-4% of total SSR\n // time on CPU profiles.\n const shellChunks: string[] = []\n let head = 0\n const bufferedEmit: Emit = (chunk) => {\n shellChunks.push(chunk)\n }\n\n // 1. Render the shell. A root-level `use(promise)` has no Suspense\n // boundary to capture it, but App Router SSR commonly suspends at this\n // level while resolving the RSC stream. Wait and retry without leaking\n // partial shell chunks or boundary ids from the aborted attempt.\n let shellRendered = false\n let rootRetries = 0\n let resources: SSRFrame['resources']\n while (!shellRendered) {\n const chunkCount = shellChunks.length\n const boundaryCount = boundaries.length\n const nextId = state.nextId\n head = 0\n const previous = beginSSR(options.identifierPrefix)\n currentSSRFrame().styleNonce = typeof options.nonce === 'object' ? options.nonce?.style : undefined\n if (resources) currentSSRFrame().resources = resources\n let suspended: Promise<unknown> | undefined\n try {\n if (state.aborted) throw state.reason\n walk(children, {\n emit: bufferedEmit,\n onSuspend: (b) => boundaries.push(b),\n nextBoundaryId: () => state.nextId++,\n onBrowserBailout: options.onBrowserBailout,\n onHead: () => { head = shellChunks.length },\n })\n shellRendered = true\n state.frame = currentSSRFrame()\n } catch (err) {\n shellChunks.length = chunkCount\n boundaries.length = boundaryCount\n state.nextId = nextId\n if (!isThenable(err)) throw err\n if (++rootRetries > 50) {\n throw new Error('renderToReadableStream exceeded 50 root suspension retries.')\n }\n suspended = err\n } finally {\n resources = currentSSRFrame().resources\n endSSR(previous)\n }\n if (suspended) await Promise.race([suspended, state.cancelled])\n }\n\n const hints = state.frame?.resources?.drain()\n if (hints) shellChunks.splice(head, 0, hints)\n if (state.frame) state.frame.shellFlushed = true\n\n // 2. Inject runtime + bootstrap scripts (once, after shell). Skip the\n // reveal/event-replay runtime when nothing needs it \u2014 no suspensions to\n // reveal and no bootstrap scripts to guard against early user input. That\n // keeps fully-static SSR responses byte-equivalent to a plain walk and\n // matches React's behavior where `renderToReadableStream` of a static\n // tree emits only the markup.\n const hasBootstrap =\n bootstrapScriptContentToArray(options.bootstrapScriptContent).length > 0 ||\n (options.bootstrapScripts?.length ?? 0) > 0 ||\n (options.bootstrapModules?.length ?? 0) > 0\n if (boundaries.length > 0 || hasBootstrap) {\n shellChunks.push(`<script${nonce ? ` nonce=\"${escapeAttr(nonce)}\"` : ''}>${BOUNDARY_REVEAL_RUNTIME}</script>`)\n for (const content of bootstrapScriptContentToArray(options.bootstrapScriptContent)) {\n shellChunks.push(inlineBootstrapTag(content, nonce))\n }\n for (const s of options.bootstrapScripts ?? []) {\n shellChunks.push(bootstrapTag(s, 'script', nonce))\n }\n for (const m of options.bootstrapModules ?? []) {\n shellChunks.push(bootstrapTag(m, 'module', nonce))\n }\n }\n\n if (shellChunks.length) emit(normalizeDocumentShell(shellChunks.join('')))\n state.onShellReady?.()\n\n // 3. Stream suspended boundaries as they resolve\n for (const b of boundaries) streamBoundary(b, emit, options, state)\n await drain(state)\n } catch (err) {\n if (isBrowserError(err)) {\n err = new Error('The server render could not complete because client rendering was requested outside a Suspense boundary.',\n Object.hasOwn(err, 'cause') ? { cause: err.cause } : undefined)\n }\n state.errored = err\n if (options.onError) options.onError(err)\n throw err\n } finally {\n state.closed = true\n }\n}\n\nfunction streamBoundary(\n b: SuspendedBoundary,\n emit: Emit,\n options: StreamOptions,\n state: OrchestratorState,\n): void {\n const nonce = scriptNonce(options)\n const task = (async () => {\n try {\n await Promise.race([b.thenable, state.cancelled])\n } catch {}\n if (state.closed) return\n\n const defer = (error: unknown) => {\n if (isBrowserError(error)) options.onBrowserBailout?.(error, { componentStack: (error as any).componentStack || b.componentStack })\n else options.onError?.(error)\n emit(`<script${nonce ? ` nonce=\"${escapeAttr(nonce)}\"` : ''}>$RB(${b.id}${isBrowserError(error) ? '' : ',1'})</script>`)\n }\n if (state.aborted) { defer(state.reason); return }\n\n // Re-render the boundary's children into a string, restoring the\n // provider stack from when the boundary first suspended.\n const parts: string[] = []\n const sub: SuspendedBoundary[] = []\n const resourceScope: ResourceScope = {}\n let styles: string[][] | undefined\n const previous = beginSSR(options.identifierPrefix, state.frame)\n state.frame?.resources?.takeStylesheets()\n const restore = applyContextSnapshot(b.contextSnapshot)\n try {\n walk(b.children, {\n emit: (s) => parts.push(s),\n onSuspend: (n) => sub.push(n),\n nextBoundaryId: () => state.nextId++,\n onBrowserBailout: options.onBrowserBailout,\n componentStack: b.componentStack,\n resourceScope,\n })\n state.frame?.resources?.mergeScope(resourceScope)\n } catch (err) {\n if (isThenable(err)) {\n streamBoundary({ ...b, thenable: err }, emit, options, state)\n } else defer(err)\n return\n } finally {\n restore()\n endSSR(previous)\n const hints = state.frame?.resources?.drain()\n styles = state.frame?.resources?.takeStylesheets()\n if (hints) emit(hints)\n }\n\n emit(`<div hidden id=\"S:${b.id}\">${parts.join('')}</div>${revealScript(b.id, nonce, styles)}`)\n\n // Recurse: any nested suspensions inside the now-revealed content\n for (const s of sub) streamBoundary(s, emit, options, state)\n })()\n state.pending.add(task)\n task.then(() => state.pending.delete(task), () => state.pending.delete(task))\n}\n\nasync function drain(state: OrchestratorState): Promise<void> {\n while (state.pending.size > 0) {\n await Promise.race(state.pending)\n }\n}\n\nfunction isThenable(value: unknown): value is Promise<unknown> {\n return !!value && typeof (value as { then?: unknown }).then === 'function'\n}\n\nfunction scriptNonce(options: StreamOptions): string | undefined {\n return typeof options.nonce === 'string' ? options.nonce : options.nonce?.script\n}\n\nfunction bootstrapScriptContentToArray(\n content: StreamOptions['bootstrapScriptContent'],\n): string[] {\n if (content === undefined) return []\n return typeof content === 'string' ? [content] : [...content]\n}\n\nfunction inlineBootstrapTag(content: string, defaultNonce: string | undefined): string {\n const nAttr = defaultNonce ? ` nonce=\"${escapeAttr(defaultNonce)}\"` : ''\n return `<script${nAttr}>${escapeScript(content)}</script>`\n}\n\nfunction normalizeDocumentShell(html: string): string {\n const doctypeIndex = html.indexOf('<!DOCTYPE html><html')\n if (doctypeIndex <= 0) return html\n\n const headPrefix = html.slice(0, doctypeIndex)\n if (!isHeadPrefix(headPrefix)) return html\n\n const documentHtml = html.slice(doctypeIndex)\n const headOpen = documentHtml.match(/<head(?:\\s[^>]*)?>/)\n if (!headOpen || headOpen.index === undefined) return html\n\n const insertAt = headOpen.index + headOpen[0].length\n return documentHtml.slice(0, insertAt) + headPrefix + documentHtml.slice(insertAt)\n}\n\nfunction isHeadPrefix(value: string): boolean {\n if (!value) return false\n return stripLeadingHeadTags(value).trim() === ''\n}\n\nfunction stripLeadingHeadTags(value: string): string {\n let rest = value\n let changed = true\n while (changed) {\n changed = false\n const next = rest.replace(\n /^\\s*(?:<meta\\b[^>]*>|<link\\b[^>]*>|<base\\b[^>]*>|<title\\b[^>]*>[\\s\\S]*?<\\/title>|<style\\b[^>]*>[\\s\\S]*?<\\/style>|<script\\b[^>]*>[\\s\\S]*?<\\/script>)/i,\n '',\n )\n if (next !== rest) {\n rest = next\n changed = true\n }\n }\n return rest\n}\n\nfunction bootstrapTag(\n entry: string | { src: string; async?: boolean; nonce?: string },\n kind: 'script' | 'module',\n defaultNonce: string | undefined,\n): string {\n const src = escapeAttr(resourceURL(typeof entry === 'string' ? entry : entry.src))\n const nonce = typeof entry === 'string' ? defaultNonce : entry.nonce ?? defaultNonce\n const nAttr = nonce ? ` nonce=\"${escapeAttr(nonce)}\"` : ''\n if (kind === 'module') return `<script type=\"module\"${nAttr} src=\"${src}\"></script>`\n return `<script async${nAttr} src=\"${src}\"></script>`\n}\n\n// ---------------------------------------------------------------------------\n// Web Streams: renderToReadableStream\n// ---------------------------------------------------------------------------\n\nexport function renderToReadableStream(\n children: ReactNode,\n options: StreamOptions = {},\n): Promise<ReadableStreamResult> {\n const state = createState()\n const encoder = new TextEncoder()\n let abortListener: (() => void) | undefined\n const detachAbortListener = () => {\n if (abortListener) {\n options.signal?.removeEventListener('abort', abortListener)\n abortListener = undefined\n }\n }\n\n let allReadyResolve!: () => void\n let allReadyReject!: (e: unknown) => void\n const allReady = new Promise<void>((r, rej) => {\n allReadyResolve = r\n allReadyReject = rej\n })\n // Shell failures reject the outer promise before callers receive allReady.\n allReady.catch(() => {})\n let shellResolve!: (stream: ReadableStreamResult) => void\n let shellReject!: (error: unknown) => void\n const shell = new Promise<ReadableStreamResult>((resolve, reject) => {\n shellResolve = resolve\n shellReject = reject\n })\n state.onShellReady = () => queueMicrotask(() => shellResolve(Object.assign(stream, { allReady })))\n\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n const emit = (chunk: string) => {\n try {\n controller.enqueue(encoder.encode(chunk))\n } catch {}\n }\n\n if (options.signal) {\n abortListener = () => {\n detachAbortListener()\n state.abort(options.signal!.reason)\n }\n options.signal.addEventListener('abort', abortListener)\n if (options.signal.aborted) abortListener()\n }\n\n streamHtml(children, emit, options, state).then(\n () => {\n detachAbortListener()\n try {\n controller.close()\n } catch {}\n allReadyResolve()\n },\n (err) => {\n detachAbortListener()\n try {\n controller.error(err)\n } catch {}\n allReadyReject(err)\n shellReject(err)\n },\n )\n\n },\n cancel(reason) {\n state.abort(reason)\n detachAbortListener()\n },\n })\n\n return shell\n}\n\n// ---------------------------------------------------------------------------\n// Node Streams: renderToPipeableStream\n// ---------------------------------------------------------------------------\n\nexport interface PipeableHandle {\n pipe<T extends PipeableWritable>(dest: T): T\n abort(reason?: unknown): void\n}\n\nexport interface PipeableOptions extends StreamOptions {\n onShellReady?: () => void\n onShellError?: (err: unknown) => void\n onAllReady?: () => void\n}\n\nexport function renderToPipeableStream(\n children: ReactNode,\n options: PipeableOptions = {},\n): PipeableHandle {\n const state = createState()\n\n const buffers: string[] = []\n let dest: PipeableWritable | null = null\n let shellReady = false\n let shellFailed = false\n let finished = false\n let failed = false\n let failure: unknown\n\n const finishDestination = (target: PipeableWritable) => {\n if (failed && target.destroy) target.destroy(failure)\n else target.end()\n }\n\n const flushTo = (w: PipeableWritable) => {\n if (!buffers.length) return\n for (const b of buffers) w.write(b)\n buffers.length = 0\n }\n\n const emit: Emit = (chunk) => {\n if (finished) return\n if (dest) dest.write(chunk)\n else buffers.push(chunk)\n }\n\n state.onShellReady = () => queueMicrotask(() => {\n if (shellFailed) return\n shellReady = true\n options.onShellReady?.()\n })\n\n // Kick off rendering\n streamHtml(children, emit, options, state).then(\n () => {\n finished = true\n if (dest) dest.end()\n options.onAllReady?.()\n },\n (err) => {\n finished = true\n failed = true\n failure = err\n if (!shellReady) {\n shellFailed = true\n options.onShellError?.(err)\n } else {\n if (dest) finishDestination(dest)\n }\n },\n )\n\n return {\n pipe<T extends PipeableWritable>(target: T): T {\n dest = target\n if (!failed) flushTo(target)\n if (finished) finishDestination(target)\n return target\n },\n abort(reason?: unknown) {\n state.abort(reason)\n },\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/server/walk.d.ts
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
|
-
import { type ReactNode } from
|
|
2
|
-
import { type ContextSnapshot } from
|
|
1
|
+
import { type ReactNode } from "../core/index.js";
|
|
2
|
+
import { type ContextSnapshot } from "./dispatcher.js";
|
|
3
|
+
import type { ResourceScope } from "./resource-hints.js";
|
|
4
|
+
export interface ServerErrorInfo {
|
|
5
|
+
componentStack: string;
|
|
6
|
+
}
|
|
7
|
+
export type BrowserBailoutCallback = (error: Error, errorInfo: ServerErrorInfo) => void;
|
|
3
8
|
export interface SuspendedBoundary {
|
|
4
9
|
id: number;
|
|
5
10
|
fallbackHTML: string;
|
|
6
11
|
children: ReactNode;
|
|
7
12
|
thenable: Promise<any>;
|
|
8
13
|
contextSnapshot: ContextSnapshot;
|
|
14
|
+
componentStack: string;
|
|
9
15
|
}
|
|
10
16
|
export interface WalkOptions {
|
|
11
17
|
emit: (chunk: string) => void;
|
|
18
|
+
onHead?: () => void;
|
|
12
19
|
onSuspend?: ((boundary: SuspendedBoundary) => void) | undefined;
|
|
20
|
+
onBrowserBailout?: BrowserBailoutCallback | undefined;
|
|
21
|
+
componentStack?: string | undefined;
|
|
22
|
+
thrownInfo?: {
|
|
23
|
+
componentStack?: string | undefined;
|
|
24
|
+
};
|
|
13
25
|
nextBoundaryId: () => number;
|
|
14
26
|
bootstrapped?: boolean | undefined;
|
|
15
27
|
isBoundaryResolution?: boolean | undefined;
|
|
16
28
|
isSvg?: boolean | undefined;
|
|
29
|
+
resourceScope?: ResourceScope | undefined;
|
|
17
30
|
/**
|
|
18
31
|
* Tracks whether the most recent emission within the *current text flow*
|
|
19
32
|
* ended with a text node. When the next emission is also text, we emit a
|
package/dist/server/walk.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
//
|
|
1
|
+
// src/server/walk.ts
|
|
2
2
|
import {
|
|
3
3
|
REACT_ELEMENT_TYPE,
|
|
4
4
|
REACT_LEGACY_ELEMENT_TYPE,
|
|
5
5
|
REACT_FRAGMENT_TYPE
|
|
6
|
-
} from "../core";
|
|
6
|
+
} from "../core/index.js";
|
|
7
7
|
import {
|
|
8
8
|
REACT_SUSPENSE_TYPE,
|
|
9
|
+
REACT_CONTEXT_TYPE,
|
|
9
10
|
REACT_PROVIDER_TYPE,
|
|
10
11
|
REACT_CONSUMER_TYPE,
|
|
11
12
|
REACT_FORWARD_REF_TYPE,
|
|
@@ -13,20 +14,26 @@ import {
|
|
|
13
14
|
REACT_LAZY_TYPE,
|
|
14
15
|
REACT_STRICT_MODE_TYPE,
|
|
15
16
|
REACT_PROFILER_TYPE,
|
|
16
|
-
REACT_PORTAL_TYPE
|
|
17
|
-
|
|
17
|
+
REACT_PORTAL_TYPE,
|
|
18
|
+
REACT_ACTIVITY_TYPE,
|
|
19
|
+
REACT_VIEW_TRANSITION_TYPE
|
|
20
|
+
} from "../react/index.js";
|
|
18
21
|
import {
|
|
19
22
|
attrToHtml,
|
|
20
23
|
escapeText,
|
|
21
24
|
escapeScript,
|
|
22
25
|
VOID_ELEMENTS,
|
|
23
26
|
RAW_TEXT_ELEMENTS
|
|
24
|
-
} from "./escape";
|
|
27
|
+
} from "./escape.js";
|
|
25
28
|
import {
|
|
26
29
|
pushContext,
|
|
27
30
|
popContext,
|
|
28
|
-
snapshotContexts
|
|
29
|
-
|
|
31
|
+
snapshotContexts,
|
|
32
|
+
recordHostResource,
|
|
33
|
+
currentSSRFrame
|
|
34
|
+
} from "./dispatcher.js";
|
|
35
|
+
import { isBrowserError } from "../core/browser.js";
|
|
36
|
+
import { resourceKind } from "../core/resource-hints.js";
|
|
30
37
|
function walk(node, opts) {
|
|
31
38
|
if (!opts.textState) opts = { ...opts, textState: { lastWasText: false } };
|
|
32
39
|
walkNode(node, opts);
|
|
@@ -86,6 +93,10 @@ function walkNode(node, opts) {
|
|
|
86
93
|
function walkElement(el, opts) {
|
|
87
94
|
const type = el.type;
|
|
88
95
|
const props = el.props ?? {};
|
|
96
|
+
if (typeof type === "string") {
|
|
97
|
+
walkHost(type, props, opts);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
89
100
|
if (type === REACT_FRAGMENT_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_PROFILER_TYPE) {
|
|
90
101
|
walkNode(props.children, opts);
|
|
91
102
|
return;
|
|
@@ -94,15 +105,19 @@ function walkElement(el, opts) {
|
|
|
94
105
|
walkSuspense(props, opts);
|
|
95
106
|
return;
|
|
96
107
|
}
|
|
97
|
-
if (
|
|
98
|
-
|
|
108
|
+
if (type === REACT_ACTIVITY_TYPE) {
|
|
109
|
+
if (props.mode !== "hidden") walkNode(props.children, opts);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (type === REACT_VIEW_TRANSITION_TYPE) {
|
|
113
|
+
walkNode(props.children, opts);
|
|
99
114
|
return;
|
|
100
115
|
}
|
|
101
116
|
const marker = type?.$$typeof;
|
|
102
117
|
if (marker === REACT_PORTAL_TYPE) {
|
|
103
118
|
return;
|
|
104
119
|
}
|
|
105
|
-
if (marker === REACT_PROVIDER_TYPE) {
|
|
120
|
+
if (marker === REACT_CONTEXT_TYPE || marker === REACT_PROVIDER_TYPE) {
|
|
106
121
|
const ctx = type._context;
|
|
107
122
|
pushContext(ctx, props.value);
|
|
108
123
|
try {
|
|
@@ -113,10 +128,9 @@ function walkElement(el, opts) {
|
|
|
113
128
|
return;
|
|
114
129
|
}
|
|
115
130
|
if (marker === REACT_CONSUMER_TYPE) {
|
|
116
|
-
const ctx = type._context;
|
|
117
131
|
const render = props.children;
|
|
118
132
|
if (typeof render === "function") {
|
|
119
|
-
walkNode(render(
|
|
133
|
+
walkNode(render(type._context._currentValue), opts);
|
|
120
134
|
}
|
|
121
135
|
return;
|
|
122
136
|
}
|
|
@@ -124,8 +138,7 @@ function walkElement(el, opts) {
|
|
|
124
138
|
const render = type.render;
|
|
125
139
|
const ref = props.ref ?? null;
|
|
126
140
|
const { ref: _omit, ...rest } = props;
|
|
127
|
-
|
|
128
|
-
walkNode(rendered, opts);
|
|
141
|
+
walkComponent(render, rest, opts, ref);
|
|
129
142
|
return;
|
|
130
143
|
}
|
|
131
144
|
if (marker === REACT_MEMO_TYPE) {
|
|
@@ -135,15 +148,8 @@ function walkElement(el, opts) {
|
|
|
135
148
|
}
|
|
136
149
|
if (marker === REACT_LAZY_TYPE) {
|
|
137
150
|
const { _payload, _init } = type;
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
walkElement({ ...el, type: resolved }, opts);
|
|
141
|
-
} catch (thenable) {
|
|
142
|
-
if (isThenable(thenable)) {
|
|
143
|
-
throw thenable;
|
|
144
|
-
}
|
|
145
|
-
throw thenable;
|
|
146
|
-
}
|
|
151
|
+
const resolved = _init(_payload);
|
|
152
|
+
walkElement({ ...el, type: resolved }, opts);
|
|
147
153
|
return;
|
|
148
154
|
}
|
|
149
155
|
if (typeof type === "function") {
|
|
@@ -153,6 +159,7 @@ function walkElement(el, opts) {
|
|
|
153
159
|
}
|
|
154
160
|
function walkHost(tag, props, opts) {
|
|
155
161
|
const isSvg = opts.isSvg || tag === "svg";
|
|
162
|
+
if (!isSvg && resourceKind(tag, props) && recordHostResource(tag, props, opts.resourceScope)) return;
|
|
156
163
|
const isTextarea = tag === "textarea";
|
|
157
164
|
const textareaValue = isTextarea ? props.value != null ? props.value : props.defaultValue : void 0;
|
|
158
165
|
const isInput = tag === "input";
|
|
@@ -164,76 +171,82 @@ function walkHost(tag, props, opts) {
|
|
|
164
171
|
pushSelectContext(val);
|
|
165
172
|
}
|
|
166
173
|
const isOption = tag === "option";
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
174
|
+
try {
|
|
175
|
+
if (tag === "html") opts.emit("<!DOCTYPE html>");
|
|
176
|
+
opts.emit("<" + tag);
|
|
177
|
+
for (const k in props) {
|
|
178
|
+
if (isTextarea && (k === "value" || k === "defaultValue")) continue;
|
|
179
|
+
if (isInput && (k === "defaultValue" || k === "defaultChecked")) continue;
|
|
180
|
+
if (isSelect && (k === "value" || k === "defaultValue")) continue;
|
|
181
|
+
if (isOption && k === "selected") continue;
|
|
182
|
+
opts.emit(attrToHtml(k, props[k], isSvg));
|
|
183
|
+
}
|
|
184
|
+
if (inputValueAttr !== void 0) {
|
|
185
|
+
opts.emit(attrToHtml("value", inputValueAttr, isSvg));
|
|
186
|
+
}
|
|
187
|
+
if (inputCheckedAttr !== void 0) {
|
|
188
|
+
opts.emit(attrToHtml("checked", inputCheckedAttr, isSvg));
|
|
189
|
+
}
|
|
190
|
+
if (isOption) {
|
|
191
|
+
const selectVal = currentSelectValue();
|
|
192
|
+
if (selectVal !== void 0) {
|
|
193
|
+
const optionValue = props.value != null ? props.value : optionChildText(props.children);
|
|
194
|
+
const matches = Array.isArray(selectVal) ? selectVal.some((v) => "" + v === "" + optionValue) : "" + selectVal === "" + optionValue;
|
|
195
|
+
if (matches) opts.emit(' selected=""');
|
|
196
|
+
} else if (props.selected) {
|
|
197
|
+
opts.emit(' selected=""');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (VOID_ELEMENTS.has(tag)) {
|
|
201
|
+
opts.emit("/>");
|
|
202
|
+
if (opts.textState) opts.textState.lastWasText = false;
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
opts.emit(">");
|
|
206
|
+
if (tag === "head") opts.onHead?.();
|
|
207
|
+
const parentTextState = opts.textState;
|
|
208
|
+
const childOpts = {
|
|
209
|
+
...opts,
|
|
210
|
+
isSvg: isSvg && tag !== "foreignObject",
|
|
211
|
+
textState: { lastWasText: false }
|
|
212
|
+
};
|
|
213
|
+
if (tag === "html" && !hasHeadChild(props.children)) {
|
|
214
|
+
opts.emit("<head>");
|
|
215
|
+
opts.onHead?.();
|
|
216
|
+
opts.emit("</head>");
|
|
217
|
+
}
|
|
218
|
+
const dangerouslyHtml = props.dangerouslySetInnerHTML?.__html;
|
|
219
|
+
if (isTextarea && textareaValue != null) {
|
|
220
|
+
opts.emit(escapeText(String(textareaValue)));
|
|
221
|
+
opts.emit(`</${tag}>`);
|
|
222
|
+
if (parentTextState) parentTextState.lastWasText = false;
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (RAW_TEXT_ELEMENTS.has(tag)) {
|
|
226
|
+
if (dangerouslyHtml != null) {
|
|
227
|
+
opts.emit(escapeScript(String(dangerouslyHtml)));
|
|
228
|
+
} else {
|
|
229
|
+
const children = props.children;
|
|
230
|
+
if (typeof children === "string" || typeof children === "number") {
|
|
231
|
+
opts.emit(escapeScript(String(children)));
|
|
232
|
+
} else if (Array.isArray(children)) {
|
|
233
|
+
opts.emit(escapeScript(children.filter((c) => c != null).join("")));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
opts.emit(`</${tag}>`);
|
|
237
|
+
if (parentTextState) parentTextState.lastWasText = false;
|
|
238
|
+
return;
|
|
190
239
|
}
|
|
191
|
-
}
|
|
192
|
-
if (VOID_ELEMENTS.has(tag)) {
|
|
193
|
-
opts.emit("/>");
|
|
194
|
-
if (opts.textState) opts.textState.lastWasText = false;
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
opts.emit(">");
|
|
198
|
-
const parentTextState = opts.textState;
|
|
199
|
-
const childOpts = {
|
|
200
|
-
...opts,
|
|
201
|
-
isSvg: isSvg && tag !== "foreignObject",
|
|
202
|
-
textState: { lastWasText: false }
|
|
203
|
-
};
|
|
204
|
-
if (tag === "html" && !hasHeadChild(props.children)) {
|
|
205
|
-
opts.emit("<head></head>");
|
|
206
|
-
}
|
|
207
|
-
const dangerouslyHtml = props.dangerouslySetInnerHTML?.__html;
|
|
208
|
-
if (isTextarea && textareaValue != null) {
|
|
209
|
-
opts.emit(escapeText(String(textareaValue)));
|
|
210
|
-
opts.emit(`</${tag}>`);
|
|
211
|
-
if (parentTextState) parentTextState.lastWasText = false;
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
if (RAW_TEXT_ELEMENTS.has(tag)) {
|
|
215
240
|
if (dangerouslyHtml != null) {
|
|
216
|
-
opts.emit(
|
|
241
|
+
opts.emit(String(dangerouslyHtml));
|
|
217
242
|
} else {
|
|
218
|
-
|
|
219
|
-
if (typeof children === "string" || typeof children === "number") {
|
|
220
|
-
opts.emit(escapeScript(String(children)));
|
|
221
|
-
} else if (Array.isArray(children)) {
|
|
222
|
-
opts.emit(escapeScript(children.filter((c) => c != null).join("")));
|
|
223
|
-
}
|
|
243
|
+
walkNode(props.children, childOpts);
|
|
224
244
|
}
|
|
225
245
|
opts.emit(`</${tag}>`);
|
|
226
246
|
if (parentTextState) parentTextState.lastWasText = false;
|
|
227
|
-
|
|
247
|
+
} finally {
|
|
248
|
+
if (isSelect) popSelectContext();
|
|
228
249
|
}
|
|
229
|
-
if (dangerouslyHtml != null) {
|
|
230
|
-
opts.emit(String(dangerouslyHtml));
|
|
231
|
-
} else {
|
|
232
|
-
walkNode(props.children, childOpts);
|
|
233
|
-
}
|
|
234
|
-
opts.emit(`</${tag}>`);
|
|
235
|
-
if (isSelect) popSelectContext();
|
|
236
|
-
if (parentTextState) parentTextState.lastWasText = false;
|
|
237
250
|
}
|
|
238
251
|
function hasHeadChild(children) {
|
|
239
252
|
if (children == null || typeof children === "boolean") return false;
|
|
@@ -253,62 +266,89 @@ function isElementOfType(value, type) {
|
|
|
253
266
|
function isIterable(value) {
|
|
254
267
|
return !!value && typeof value[Symbol.iterator] === "function";
|
|
255
268
|
}
|
|
256
|
-
function walkComponent(fn, props, opts) {
|
|
257
|
-
if (
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
|
|
269
|
+
function walkComponent(fn, props, opts, ref) {
|
|
270
|
+
if (opts.onBrowserBailout) {
|
|
271
|
+
opts = { ...opts, componentStack: `
|
|
272
|
+
at ${fn.displayName || fn.name || "Anonymous"}${opts.componentStack || ""}` };
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
if (fn.prototype?.isReactComponent) {
|
|
276
|
+
const ctxType = fn.contextType;
|
|
277
|
+
const ctxValue = ctxType ? ctxType._currentValue : void 0;
|
|
278
|
+
const instance = new fn(props, ctxValue);
|
|
279
|
+
instance.props = props;
|
|
280
|
+
instance.context = ctxValue;
|
|
281
|
+
if (fn.getDerivedStateFromProps) {
|
|
282
|
+
const d = fn.getDerivedStateFromProps(props, instance.state);
|
|
283
|
+
if (d) instance.state = { ...instance.state, ...d };
|
|
284
|
+
}
|
|
285
|
+
walkNode(instance.render(), opts);
|
|
286
|
+
return;
|
|
266
287
|
}
|
|
267
|
-
|
|
268
|
-
|
|
288
|
+
const rendered = fn(props, ref);
|
|
289
|
+
walkNode(rendered, opts);
|
|
290
|
+
} catch (error) {
|
|
291
|
+
if (opts.thrownInfo && !opts.thrownInfo.componentStack) opts.thrownInfo.componentStack = opts.componentStack;
|
|
292
|
+
if (isBrowserError(error) && !error.componentStack) {
|
|
293
|
+
Object.defineProperty(error, "componentStack", { value: opts.componentStack });
|
|
294
|
+
}
|
|
295
|
+
throw error;
|
|
269
296
|
}
|
|
270
|
-
const rendered = fn(props);
|
|
271
|
-
walkNode(rendered, opts);
|
|
272
297
|
}
|
|
273
298
|
function walkSuspense(props, opts) {
|
|
274
299
|
const id = opts.nextBoundaryId();
|
|
275
300
|
const contextSnapshot = snapshotContexts();
|
|
276
301
|
const childParts = [];
|
|
302
|
+
const nested = [];
|
|
303
|
+
const thrownInfo = {};
|
|
277
304
|
const childEmit = (s) => childParts.push(s);
|
|
305
|
+
const resourceScope = currentSSRFrame().shellFlushed ? {} : void 0;
|
|
278
306
|
try {
|
|
279
307
|
walkNode(props.children, {
|
|
308
|
+
...opts,
|
|
309
|
+
resourceScope,
|
|
310
|
+
thrownInfo,
|
|
280
311
|
emit: childEmit,
|
|
281
|
-
onSuspend: opts.onSuspend,
|
|
312
|
+
onSuspend: opts.onSuspend ? (boundary) => nested.push(boundary) : void 0,
|
|
282
313
|
nextBoundaryId: opts.nextBoundaryId
|
|
283
314
|
});
|
|
284
315
|
} catch (thenable) {
|
|
285
|
-
|
|
316
|
+
nested.length = 0;
|
|
317
|
+
if (isThenable(thenable) || isBrowserError(thenable)) {
|
|
286
318
|
const fallbackParts = [];
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
319
|
+
walkNode(props.fallback, {
|
|
320
|
+
...opts,
|
|
321
|
+
emit: (s) => fallbackParts.push(s),
|
|
322
|
+
onSuspend: opts.onSuspend ? (boundary) => nested.push(boundary) : void 0,
|
|
323
|
+
nextBoundaryId: opts.nextBoundaryId
|
|
324
|
+
});
|
|
325
|
+
if (isBrowserError(thenable)) {
|
|
326
|
+
opts.onBrowserBailout?.(thenable, { componentStack: thenable.componentStack || opts.componentStack || "" });
|
|
327
|
+
opts.emit(`<!--$!${id}-->${fallbackParts.join("")}<!--/$-->`);
|
|
328
|
+
for (const boundary of nested) opts.onSuspend?.(boundary);
|
|
329
|
+
return;
|
|
294
330
|
}
|
|
295
331
|
emitBoundary(opts, id, fallbackParts.join(""));
|
|
332
|
+
for (const boundary of nested) opts.onSuspend?.(boundary);
|
|
296
333
|
if (opts.onSuspend) {
|
|
297
334
|
opts.onSuspend({
|
|
298
335
|
id,
|
|
299
336
|
fallbackHTML: fallbackParts.join(""),
|
|
300
337
|
children: props.children,
|
|
301
338
|
thenable,
|
|
302
|
-
contextSnapshot
|
|
339
|
+
contextSnapshot,
|
|
340
|
+
componentStack: thrownInfo.componentStack || opts.componentStack || ""
|
|
303
341
|
});
|
|
304
342
|
}
|
|
305
343
|
return;
|
|
306
344
|
}
|
|
307
345
|
throw thenable;
|
|
308
346
|
}
|
|
347
|
+
if (resourceScope) currentSSRFrame().resources?.mergeScope(resourceScope, opts.resourceScope);
|
|
309
348
|
opts.emit(`<!--$${id}-->`);
|
|
310
349
|
opts.emit(childParts.join(""));
|
|
311
350
|
opts.emit(`<!--/$-->`);
|
|
351
|
+
for (const boundary of nested) opts.onSuspend?.(boundary);
|
|
312
352
|
}
|
|
313
353
|
function emitBoundary(opts, id, fallbackHTML) {
|
|
314
354
|
opts.emit(`<!--$?${id}--><div id="B:${id}">`);
|