UNPKG

@tanstack/router-core

Version:

Modern and scalable routing for React applications

1 lines 29.4 kB
{"version":3,"file":"hydrationScripts.cjs","names":[],"sources":["../../../src/ssr/hydrationScripts.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/triple-slash-reference */\n/// <reference path=\"../vite-env.d.ts\" />\n\nimport { getCrossReferenceHeader } from 'seroval'\nimport { invariant } from '../invariant'\nimport minifiedTsrBootStrapScript from './tsrScript?script-string'\nimport { GLOBAL_TSR } from './constants'\nimport { encodeIntoBoundedChunk } from './htmlBoundaryScanner'\nimport type { RouterManagedTag } from '../manifest'\n\nexport const SSR_SERIALIZATION_SCOPE_ID = 'tsr'\nconst HYDRATION_SCRIPT_BOUNDARY_TAIL = ';/*$tsr-stream-boundary*/'\n\nconst encoder = new TextEncoder()\nconst SOURCE_SEPARATOR = ';'\nconst MAX_INITIAL_SOURCE_CODE_UNITS = 16 * 1024\nconst MAX_BACKLOG_CODE_UNITS = 16 * 1024 * 1024\nconst MAX_BACKLOG_SOURCES = 4_096\nconst MIN_OUTPUT_BYTES = 256\nconst MAX_DIRECT_CODE_UNITS = 16 * 1024\nexport const MAX_HYDRATION_OUTPUT_CHUNK_BYTES = 64 * 1024\nconst MAX_DYNAMIC_RECORD_CODE_UNITS = MAX_HYDRATION_OUTPUT_CHUNK_BYTES\n\nconst STREAM_PART_ATTRIBUTE = 'data-tsr-stream-part'\nconst INITIAL_CLEANUP_SOURCE = `{let s=document.currentScript,p;while((p=s.previousElementSibling)&&p.hasAttribute('${STREAM_PART_ATTRIBUTE}'))p.remove();s.remove()}`\nconst INITIAL_CLEANUP_SUFFIX = SOURCE_SEPARATOR + INITIAL_CLEANUP_SOURCE\nconst DYNAMIC_CLOSE_SOURCE = 'document.currentScript.remove()</script>'\nconst HYDRATION_SCRIPT_BOUNDARY_SOURCE =\n `document.currentScript.remove()` + HYDRATION_SCRIPT_BOUNDARY_TAIL\nconst HYDRATION_SCRIPT_BOUNDARY_SUFFIX =\n HYDRATION_SCRIPT_BOUNDARY_TAIL + '</script>'\nexport const HYDRATION_SCRIPT_BOUNDARY_ANCHOR_INDEX =\n HYDRATION_SCRIPT_BOUNDARY_SUFFIX.lastIndexOf('*')\nexport const HYDRATION_SCRIPT_BOUNDARY_BYTES = encoder.encode(\n HYDRATION_SCRIPT_BOUNDARY_SUFFIX,\n)\n\nconst ROUTER_PREFIX = GLOBAL_TSR + '.router='\nconst PROMISE_PREFIX = GLOBAL_TSR + '.p(()=>'\nconst DEFAULT_INITIAL_SOURCES = [\n getCrossReferenceHeader(SSR_SERIALIZATION_SCOPE_ID),\n minifiedTsrBootStrapScript,\n]\n\nexport const HydrationScriptOutputState = {\n Waiting: 0,\n Ready: 1,\n Active: 2,\n Done: 3,\n Failed: 4,\n} as const\n\nexport type HydrationScriptOutputState =\n (typeof HydrationScriptOutputState)[keyof typeof HydrationScriptOutputState]\n\n/** A request-local, single-consumer stream of complete records. */\nexport type HydrationScriptOutput = {\n readonly state: HydrationScriptOutputState\n readonly error: unknown\n pullChunk: () => Uint8Array\n subscribe: (onChange: () => void) => () => void\n}\n\ntype ConsumerOwnership =\n | HydrationScriptOutput\n | 'fast-path'\n | 'cleaned'\n | undefined\n\n/** The one-time initial `<Scripts>` take: hydration tags plus the boundary. */\nexport type InitialHydrationScriptTags = {\n before: Array<RouterManagedTag>\n boundary: RouterManagedTag\n}\n\nfunction escapeAttribute(value: string) {\n return value.replace(/[&\"'<>]/g, (char) => `&#${char.charCodeAt(0)};`)\n}\n\nfunction createInitialTags(\n sources: ReadonlyArray<string>,\n nonce: string | undefined,\n): InitialHydrationScriptTags {\n const before: Array<RouterManagedTag> = []\n for (const source of sources) {\n if (!source) {\n continue\n }\n const previous = before[before.length - 1]\n if (\n previous?.children &&\n previous.children.length + SOURCE_SEPARATOR.length + source.length <=\n MAX_INITIAL_SOURCE_CODE_UNITS\n ) {\n previous.children += SOURCE_SEPARATOR + source\n } else {\n before.push({\n tag: 'script',\n attrs: { nonce, [STREAM_PART_ATTRIBUTE]: '' },\n children: source,\n })\n }\n }\n // Cleanup runs before route and asset scripts. If hydration code fails, its\n // transport tags can remain because that page cannot hydrate successfully.\n const lastHydrationTag = before[before.length - 1]\n if (lastHydrationTag) {\n const lastSource = lastHydrationTag.children!\n if (\n lastSource.length + INITIAL_CLEANUP_SUFFIX.length <=\n MAX_INITIAL_SOURCE_CODE_UNITS\n ) {\n lastHydrationTag.children = lastSource + INITIAL_CLEANUP_SUFFIX\n } else {\n // Do not concatenate onto a large source. A renderer could flatten the\n // result and temporarily retain a second copy of the hydration payload.\n before.push({\n tag: 'script',\n attrs: { nonce, [STREAM_PART_ATTRIBUTE]: '' },\n children: INITIAL_CLEANUP_SOURCE,\n })\n }\n }\n return {\n before,\n boundary: {\n tag: 'script',\n attrs: { nonce },\n children: HYDRATION_SCRIPT_BOUNDARY_SOURCE,\n } satisfies RouterManagedTag,\n }\n}\n\ntype HydrationScripts = {\n pushSerializedSource: (\n data: string,\n initial: boolean,\n wrap: boolean,\n ) => boolean\n pushSource: (nextSource: string) => boolean\n fail: (reason: unknown) => void\n finish: () => void\n takeInitialHydrationScriptTags: () => InitialHydrationScriptTags | undefined\n disableHydration: () => void\n isInitialTaken: () => boolean\n skipInitialTake: () => void\n liftBarrier: () => void\n claimOutput: () => HydrationScriptOutput\n reserveFastPath: (output?: HydrationScriptOutput) => boolean\n startSerializationTimeout: (timeoutMs: number) => void\n cleanup: () => void\n}\n\nclass HydrationScriptsOwner implements HydrationScriptOutput {\n private queuedSources: Array<string | undefined> = []\n private queuedSourceHead = 0\n private initialTaken = false\n private barrierLifted = false\n private producerDone = false\n private consumer: ConsumerOwnership\n private listener: (() => void) | undefined\n\n private active: Array<string | undefined> | undefined\n private retainedSources = 0\n private regularCodeUnits = 0\n private hasOversizedSource = false\n\n private segmentIndex = 0\n private closingSegmentIndex = 0\n private source = ''\n private sourceOffset = 0\n private outputCapacity = MIN_OUTPUT_BYTES\n\n private outputState: HydrationScriptOutputState =\n HydrationScriptOutputState.Waiting\n private outputError: unknown\n private timeout: ReturnType<typeof setTimeout> | undefined\n private opening: string | undefined\n\n constructor(\n private readonly nonce: string | undefined,\n initialSources?: ReadonlyArray<string>,\n ) {\n // ServerSsr exposes this method as a bare callback, so keep this single\n // method bound while all other owner operations live on the prototype.\n this.takeInitialHydrationScriptTags =\n this.takeInitialHydrationScriptTags.bind(this)\n\n const seedSources = initialSources ?? DEFAULT_INITIAL_SOURCES\n for (const seedSource of seedSources) {\n if (!this.account(seedSource)) {\n break\n }\n this.queuedSources.push(seedSource)\n }\n }\n\n get state() {\n return this.outputState\n }\n\n get error() {\n return this.outputError\n }\n\n private notify() {\n try {\n this.listener?.()\n } catch (listenerError) {\n console.error('Hydration script output listener error:', listenerError)\n }\n }\n\n private refresh(notifyChange = true) {\n const next =\n this.outputState === HydrationScriptOutputState.Failed\n ? HydrationScriptOutputState.Failed\n : this.active\n ? HydrationScriptOutputState.Active\n : typeof this.consumer === 'object' &&\n this.initialTaken &&\n this.barrierLifted &&\n !this.queueIsEmpty()\n ? HydrationScriptOutputState.Ready\n : this.producerDone && this.initialTaken && this.queueIsEmpty()\n ? HydrationScriptOutputState.Done\n : HydrationScriptOutputState.Waiting\n if (this.outputState !== next) {\n this.outputState = next\n if (notifyChange) {\n this.notify()\n }\n }\n }\n\n private clearTimeoutIfSet() {\n if (this.timeout !== undefined) {\n clearTimeout(this.timeout)\n this.timeout = undefined\n }\n }\n\n private queueIsEmpty() {\n return this.queuedSourceHead === this.queuedSources.length\n }\n\n private clearQueue() {\n this.queuedSources = []\n this.queuedSourceHead = 0\n }\n\n private dropBufferedOutput() {\n this.clearQueue()\n this.active = undefined\n this.retainedSources = 0\n this.regularCodeUnits = 0\n this.hasOversizedSource = false\n this.segmentIndex = 0\n this.closingSegmentIndex = 0\n this.source = ''\n this.sourceOffset = 0\n this.outputCapacity = MIN_OUTPUT_BYTES\n this.opening = undefined\n }\n\n fail(reason: unknown) {\n if (\n this.consumer === 'cleaned' ||\n this.outputState === HydrationScriptOutputState.Failed\n ) {\n return\n }\n this.outputError = reason\n this.clearTimeoutIfSet()\n this.dropBufferedOutput()\n this.outputState = HydrationScriptOutputState.Failed\n this.notify()\n }\n\n private rejectBacklog(kind: 'source-part' | 'code-unit') {\n this.fail(new Error(`SSR hydration backlog exceeded maximum ${kind} count`))\n return false\n }\n\n private account(nextSource: string) {\n if (this.retainedSources === MAX_BACKLOG_SOURCES) {\n return this.rejectBacklog('source-part')\n }\n if (nextSource.length > MAX_BACKLOG_CODE_UNITS) {\n if (this.hasOversizedSource) {\n return this.rejectBacklog('code-unit')\n }\n this.hasOversizedSource = true\n } else if (\n this.regularCodeUnits + nextSource.length >\n MAX_BACKLOG_CODE_UNITS\n ) {\n return this.rejectBacklog('code-unit')\n } else {\n this.regularCodeUnits += nextSource.length\n }\n this.retainedSources++\n return true\n }\n\n private releaseSource(part: string) {\n this.retainedSources--\n if (part.length > MAX_BACKLOG_CODE_UNITS) {\n this.hasOversizedSource = false\n } else {\n this.regularCodeUnits -= part.length\n }\n }\n\n private releaseAccounting(batch: ReadonlyArray<string | undefined>) {\n for (const part of batch) {\n if (part !== undefined) {\n this.releaseSource(part)\n }\n }\n }\n\n liftBarrier() {\n if (this.consumer !== 'cleaned' && !this.barrierLifted) {\n this.barrierLifted = true\n this.refresh()\n }\n }\n\n private producerCanWrite() {\n return (\n this.consumer !== 'cleaned' &&\n this.outputState !== HydrationScriptOutputState.Failed &&\n !this.producerDone\n )\n }\n\n pushSource(nextSource: string) {\n if (!this.producerCanWrite()) {\n return false\n }\n if (this.account(nextSource)) {\n this.queuedSources.push(nextSource)\n if (this.initialTaken) {\n this.refresh()\n }\n } else {\n return false\n }\n // A notification can synchronously fail or clean up this owner.\n return this.producerCanWrite()\n }\n\n private takeQueuedBatch(batchLength: number) {\n if (\n this.queuedSourceHead === 0 &&\n batchLength === this.queuedSources.length\n ) {\n const batch = this.queuedSources\n this.clearQueue()\n return batch\n }\n const end = this.queuedSourceHead + batchLength\n const batch = this.queuedSources.slice(this.queuedSourceHead, end)\n for (let index = this.queuedSourceHead; index < end; index++) {\n this.queuedSources[index] = undefined\n }\n this.queuedSourceHead = end\n if (this.queueIsEmpty()) {\n this.clearQueue()\n } else if (\n this.queuedSourceHead >= 1024 &&\n this.queuedSourceHead >= this.queuedSources.length - this.queuedSourceHead\n ) {\n this.queuedSources = this.queuedSources.slice(this.queuedSourceHead)\n this.queuedSourceHead = 0\n }\n return batch\n }\n\n private release(batch: Array<string | undefined>) {\n this.releaseAccounting(batch)\n this.active = undefined\n this.source = ''\n this.sourceOffset = 0\n this.refresh(false)\n }\n\n private advanceSource() {\n const batch = this.active!\n if (this.segmentIndex > 0 && this.segmentIndex < this.closingSegmentIndex) {\n const partIndex = (this.segmentIndex - 1) >> 1\n if (this.segmentIndex % 2 === 1) {\n const part = batch[partIndex]\n if (part !== undefined) {\n this.releaseSource(part)\n batch[partIndex] = undefined\n }\n }\n }\n this.segmentIndex++\n // Segment 0 is the opening tag. Sources and separators alternate until\n // the closing segment. The next advance releases the complete record.\n if (this.segmentIndex < this.closingSegmentIndex) {\n const partIndex = (this.segmentIndex - 1) >> 1\n this.source =\n this.segmentIndex % 2 === 1 ? batch[partIndex]! : SOURCE_SEPARATOR\n } else if (this.segmentIndex === this.closingSegmentIndex) {\n this.source = DYNAMIC_CLOSE_SOURCE\n } else {\n this.release(batch)\n }\n this.sourceOffset = 0\n }\n\n private pullActive() {\n const bytes = new Uint8Array(this.outputCapacity)\n let offset = 0\n while (this.active) {\n if (this.sourceOffset === this.source.length) {\n this.advanceSource()\n } else if (offset === bytes.length) {\n break\n } else {\n const result = encodeIntoBoundedChunk(\n this.source,\n this.sourceOffset,\n bytes,\n offset,\n )\n if (result.read === 0) {\n break\n }\n this.sourceOffset += result.read\n offset += result.written\n }\n }\n if (offset === 0) {\n throw new Error('SSR router script record produced no output')\n }\n if (offset === bytes.length) {\n return bytes\n }\n // A subarray view pins the whole output buffer. Copy mostly-empty tail\n // chunks (typically the final close-tag remnant) so the large buffer can\n // be collected immediately.\n return offset * 2 < bytes.length\n ? bytes.slice(0, offset)\n : bytes.subarray(0, offset)\n }\n\n private pullReady() {\n const scriptOpening = (this.opening ??= this.nonce\n ? `<script nonce=\"${escapeAttribute(this.nonce)}\">`\n : '<script>')\n let codeUnits = scriptOpening.length + DYNAMIC_CLOSE_SOURCE.length\n let batchLength = 0\n for (\n let index = this.queuedSourceHead;\n index < this.queuedSources.length;\n index++\n ) {\n const part = this.queuedSources[index]!\n const nextCodeUnits = codeUnits + SOURCE_SEPARATOR.length + part.length\n if (batchLength > 0 && nextCodeUnits > MAX_DYNAMIC_RECORD_CODE_UNITS) {\n break\n }\n codeUnits = nextCodeUnits\n batchLength++\n if (codeUnits > MAX_DYNAMIC_RECORD_CODE_UNITS) {\n // A complete JavaScript source is not safely splittable across tags.\n break\n }\n }\n const batch = this.takeQueuedBatch(batchLength)\n if (codeUnits <= MAX_DIRECT_CODE_UNITS) {\n const joined =\n batch.length === 1 ? batch[0]! : batch.join(SOURCE_SEPARATOR)\n const bytes = encoder.encode(\n scriptOpening + joined + SOURCE_SEPARATOR + DYNAMIC_CLOSE_SOURCE,\n )\n this.release(batch)\n return bytes\n }\n this.active = batch\n this.segmentIndex = 0\n this.closingSegmentIndex = (batch.length << 1) + 1\n this.source = scriptOpening\n this.sourceOffset = 0\n this.outputCapacity = Math.max(\n MIN_OUTPUT_BYTES,\n Math.min(MAX_HYDRATION_OUTPUT_CHUNK_BYTES, codeUnits),\n )\n this.outputState = HydrationScriptOutputState.Active\n return this.pullActive()\n }\n\n pullChunk() {\n if (\n this.outputState !== HydrationScriptOutputState.Ready &&\n this.outputState !== HydrationScriptOutputState.Active\n ) {\n throw new Error('Hydration script output is not ready')\n }\n try {\n return this.outputState === HydrationScriptOutputState.Ready\n ? this.pullReady()\n : this.pullActive()\n } catch (cause) {\n this.fail(cause)\n throw cause\n }\n }\n\n subscribe(onChange: () => void) {\n if (this.consumer === 'cleaned') {\n return () => {}\n }\n if (this.listener) {\n throw new Error('SSR hydration output already has a subscriber')\n }\n this.listener = onChange\n return () => {\n if (this.listener === onChange) {\n this.listener = undefined\n }\n }\n }\n\n pushSerializedSource(data: string, initial: boolean, wrap: boolean) {\n let serialized = initial ? ROUTER_PREFIX + data : data\n if (wrap) {\n serialized = PROMISE_PREFIX + serialized + ')'\n }\n return this.pushSource(serialized)\n }\n\n finish() {\n if (!this.pushSource(GLOBAL_TSR + '.e()')) {\n return\n }\n this.producerDone = true\n this.clearTimeoutIfSet()\n this.refresh()\n }\n\n takeInitialHydrationScriptTags() {\n if (\n this.consumer === 'cleaned' ||\n this.outputState === HydrationScriptOutputState.Failed ||\n this.initialTaken\n ) {\n return undefined\n }\n // No source can drain before the initial take, so the queue has no\n // cleared prefix. Once tags are composed, the same empty array can become\n // the dynamic queue without allocating a replacement.\n const sources = this.queuedSources as Array<string>\n const tags = createInitialTags(sources, this.nonce)\n this.initialTaken = true\n this.releaseAccounting(sources)\n sources.length = 0\n this.queuedSourceHead = 0\n this.refresh()\n return tags\n }\n\n /**\n * Opt this request out of hydration output entirely (for example a\n * `hydrate: false` page). Drops the queued bootstrap sources, marks the\n * producer done, and makes the fast pass-through path reservable without\n * a rendered `<Scripts>` boundary. Must run before the initial take and\n * before serialization produces output.\n */\n disableHydration() {\n if (\n this.consumer === 'cleaned' ||\n this.outputState === HydrationScriptOutputState.Failed\n ) {\n return\n }\n if (this.initialTaken || this.consumer !== undefined || this.producerDone) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n 'Invariant failed: hydration output is already committed; ' +\n 'disableHydration() must run before <Scripts> renders and ' +\n 'before serialization starts.',\n )\n }\n\n invariant()\n }\n this.releaseAccounting(this.queuedSources)\n this.clearQueue()\n this.initialTaken = true\n this.barrierLifted = true\n this.producerDone = true\n this.refresh()\n }\n\n // The rendered boundary can only exist after the initial take. The merger\n // uses this to skip barrier scanning for all earlier renderer bytes.\n isInitialTaken() {\n return this.initialTaken\n }\n\n // Application EOF without a rendered <Scripts> boundary. The initial\n // sources become late records after the document so the response still\n // completes instead of failing after its HTML was already delivered.\n skipInitialTake() {\n if (this.consumer !== 'cleaned' && !this.initialTaken) {\n this.initialTaken = true\n this.refresh()\n }\n }\n\n claimOutput(): HydrationScriptOutput {\n if (this.consumer === 'cleaned') {\n throw new Error('SSR hydration script output is already cleaned up')\n }\n if (this.consumer !== undefined) {\n throw new Error('SSR hydration script output already has a consumer')\n }\n this.consumer = this\n this.refresh(false)\n return this\n }\n\n reserveFastPath(output?: HydrationScriptOutput) {\n const ownsConsumer = this.consumer === output\n if (\n this.outputState === HydrationScriptOutputState.Failed ||\n !this.producerDone ||\n !this.initialTaken ||\n !this.queueIsEmpty() ||\n this.active ||\n !ownsConsumer\n ) {\n return false\n }\n this.consumer = 'fast-path'\n return true\n }\n\n // Arms the serialization deadline once the renderer finished. The\n // lifecycle signal stays separate from this merge-transport concern.\n startSerializationTimeout(timeoutMs: number) {\n if (\n this.consumer === 'cleaned' ||\n this.outputState === HydrationScriptOutputState.Failed ||\n this.producerDone ||\n this.timeout !== undefined\n ) {\n return\n }\n this.timeout = setTimeout(() => {\n this.timeout = undefined\n if (\n this.consumer !== 'cleaned' &&\n this.outputState !== HydrationScriptOutputState.Failed &&\n !this.producerDone\n ) {\n console.error('Serialization timeout after app render finished')\n this.fail(new Error('Serialization timeout after app render finished'))\n }\n }, timeoutMs)\n }\n\n cleanup() {\n if (this.consumer === 'cleaned') {\n return\n }\n this.consumer = 'cleaned'\n this.clearTimeoutIfSet()\n this.dropBufferedOutput()\n this.listener = undefined\n this.outputError = undefined\n this.producerDone = true\n this.outputState = HydrationScriptOutputState.Done\n }\n}\n\n/** Create the hydration-script owner for one server request. */\nexport function createHydrationScripts(\n nonce: string | undefined,\n initialSources?: ReadonlyArray<string>,\n): HydrationScripts {\n return new HydrationScriptsOwner(nonce, initialSources)\n}\n"],"mappings":"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"}