| 1 | /** |
| 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. |
| 3 | * |
| 4 | * This source code is licensed under the MIT license found in the |
| 5 | * LICENSE file in the root directory of this source tree. |
| 6 | * |
| 7 | * @flow |
| 8 | */ |
| 9 | |
| 10 | import type {ReactNodeList} from 'shared/ReactTypes'; |
| 11 | |
| 12 | import type {Request, ErrorInfo} from 'react-server/src/ReactFizzServer'; |
| 13 | |
| 14 | import type {Destination} from 'react-server/src/ReactServerStreamConfig'; |
| 15 | import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM'; |
| 16 | |
| 17 | import { |
| 18 | createRequest, |
| 19 | startWork, |
| 20 | performWork, |
| 21 | startFlowing, |
| 22 | abort, |
| 23 | } from 'react-server/src/ReactFizzServer'; |
| 24 | |
| 25 | import { |
| 26 | createResumableState, |
| 27 | createRenderState, |
| 28 | createRootFormatContext, |
| 29 | } from 'react-server/src/ReactFizzConfig'; |
| 30 | |
| 31 | type Options = { |
| 32 | identifierPrefix?: string, |
| 33 | bootstrapScriptContent?: string, |
| 34 | bootstrapScripts: Array<string>, |
| 35 | bootstrapModules: Array<string>, |
| 36 | progressiveChunkSize?: number, |
| 37 | onError: (error: mixed) => void, |
| 38 | onBrowserBailout?: (error: mixed, errorInfo: ErrorInfo) => void, |
| 39 | unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor, |
| 40 | }; |
| 41 | |
| 42 | opaque type Stream = { |
| 43 | destination: Destination, |
| 44 | request: Request, |
| 45 | }; |
| 46 | |
| 47 | function renderToStream(children: ReactNodeList, options: Options): Stream { |
| 48 | const destination: Destination = { |
| 49 | buffer: '', |
| 50 | done: false, |
| 51 | fatal: false, |
| 52 | error: null, |
| 53 | }; |
| 54 | const resumableState = createResumableState( |
| 55 | options ? options.identifierPrefix : undefined, |
| 56 | options ? options.unstable_externalRuntimeSrc : undefined, |
| 57 | options ? options.bootstrapScriptContent : undefined, |
| 58 | options ? options.bootstrapScripts : undefined, |
| 59 | options ? options.bootstrapModules : undefined, |
| 60 | ); |
| 61 | const request = createRequest( |
| 62 | children, |
| 63 | resumableState, |
| 64 | createRenderState( |
| 65 | resumableState, |
| 66 | undefined, |
| 67 | options ? options.unstable_externalRuntimeSrc : undefined, |
| 68 | ), |
| 69 | createRootFormatContext(undefined), |
| 70 | options ? options.progressiveChunkSize : undefined, |
| 71 | options.onError, |
| 72 | options.onBrowserBailout, |
| 73 | undefined, |
| 74 | undefined, |
| 75 | ); |
| 76 | startWork(request); |
| 77 | if (destination.fatal) { |
| 78 | throw destination.error; |
| 79 | } |
| 80 | return { |
| 81 | destination, |
| 82 | request, |
| 83 | }; |
| 84 | } |
| 85 | |
| 86 | function abortStream(stream: Stream, reason: mixed): void { |
| 87 | abort(stream.request, reason); |
| 88 | } |
| 89 | |
| 90 | function renderNextChunk(stream: Stream): string { |
| 91 | const {request, destination} = stream; |
| 92 | performWork(request); |
| 93 | startFlowing(request, destination); |
| 94 | if (destination.fatal) { |
| 95 | throw destination.error; |
| 96 | } |
| 97 | const chunk = destination.buffer; |
| 98 | destination.buffer = ''; |
| 99 | return chunk; |
| 100 | } |
| 101 | |
| 102 | function hasFinished(stream: Stream): boolean { |
| 103 | return stream.destination.done; |
| 104 | } |
| 105 | |
| 106 | function debug(stream: Stream): any { |
| 107 | // convert to any to silence flow errors from opaque type |
| 108 | const request = stream.request as any; |
| 109 | return { |
| 110 | pendingRootTasks: request.pendingRootTasks, |
| 111 | clientRenderedBoundaries: request.clientRenderedBoundaries.length, |
| 112 | completedBoundaries: request.completedBoundaries.length, |
| 113 | partialBoundaries: request.partialBoundaries.length, |
| 114 | allPendingTasks: request.allPendingTasks, |
| 115 | pingedTasks: request.pingedTasks.length, |
| 116 | }; |
| 117 | } |
| 118 | |
| 119 | export {renderToStream, renderNextChunk, hasFinished, abortStream, debug}; |