8
8
*/
9
9
10
10
import type { ReactNodeList } from 'shared/ReactTypes' ;
11
-
12
- import type {
13
- Request ,
14
- PostponedState ,
15
- ErrorInfo ,
16
- } from 'react-server/src/ReactFizzServer' ;
11
+ import type { LazyComponent } from 'react/src/ReactLazy' ;
17
12
18
13
import ReactVersion from 'shared/ReactVersion' ;
19
14
20
15
import {
21
- createRequest ,
22
- startWork ,
23
- startFlowing ,
24
- abort ,
16
+ createRequest as createFlightRequest ,
17
+ startWork as startFlightWork ,
18
+ startFlowing as startFlightFlowing ,
19
+ abort as abortFlight ,
20
+ } from 'react-server/src/ReactFlightServer' ;
21
+
22
+ import {
23
+ createResponse as createFlightResponse ,
24
+ getRoot as getFlightRoot ,
25
+ processBinaryChunk as processFlightBinaryChunk ,
26
+ close as closeFlight ,
27
+ } from 'react-client/src/ReactFlightClient' ;
28
+
29
+ import {
30
+ createRequest as createFizzRequest ,
31
+ startWork as startFizzWork ,
32
+ startFlowing as startFizzFlowing ,
33
+ abort as abortFizz ,
25
34
} from 'react-server/src/ReactFizzServer' ;
26
35
27
36
import {
@@ -30,20 +39,60 @@ import {
30
39
createRootFormatContext ,
31
40
} from 'react-dom-bindings/src/server/ReactFizzConfigDOMLegacy' ;
32
41
42
+ type ReactMarkupNodeList =
43
+ // This is the intersection of ReactNodeList and ReactClientValue minus
44
+ // Client/ServerReferences.
45
+ | React$Element < React$AbstractComponent < any , any >>
46
+ | LazyComponent < ReactMarkupNodeList , any >
47
+ | React$Element < string >
48
+ | string
49
+ | boolean
50
+ | number
51
+ | symbol
52
+ | null
53
+ | void
54
+ | bigint
55
+ | $AsyncIterable < ReactMarkupNodeList , ReactMarkupNodeList , void >
56
+ | $AsyncIterator < ReactMarkupNodeList , ReactMarkupNodeList , void >
57
+ | Iterable < ReactMarkupNodeList >
58
+ | Iterator < ReactMarkupNodeList >
59
+ | Array < ReactMarkupNodeList >
60
+ | Promise < ReactMarkupNodeList > ; // Thenable<ReactMarkupNodeList>
61
+
33
62
type MarkupOptions = {
34
63
identifierPrefix ?: string ,
35
64
signal ?: AbortSignal ,
36
65
} ;
37
66
67
+ function noServerCallOrFormAction ( ) {
68
+ throw new Error (
69
+ 'renderToMarkup should not have emitted Server References. This is a bug in React.' ,
70
+ ) ;
71
+ }
72
+
38
73
export function renderToMarkup (
39
- children : ReactNodeList ,
74
+ children : ReactMarkupNodeList ,
40
75
options ?: MarkupOptions ,
41
76
) : Promise < string > {
42
77
return new Promise ( ( resolve , reject ) => {
43
- let didFatal = false ;
44
- let fatalError = null ;
78
+ const textEncoder = new TextEncoder ( ) ;
79
+ const flightDestination = {
80
+ push ( chunk : string | null ) : boolean {
81
+ if ( chunk !== null ) {
82
+ // TODO: Legacy should not use binary streams.
83
+ processFlightBinaryChunk ( flightResponse , textEncoder . encode ( chunk ) ) ;
84
+ } else {
85
+ closeFlight ( flightResponse ) ;
86
+ }
87
+ return true ;
88
+ } ,
89
+ destroy ( error : mixed ) : void {
90
+ abortFizz ( fizzRequest , error ) ;
91
+ reject ( error ) ;
92
+ } ,
93
+ } ;
45
94
let buffer = '';
46
- const destination = {
95
+ const fizzDestination = {
47
96
// $FlowFixMe[missing-local-annot]
48
97
push ( chunk ) {
49
98
if ( chunk !== null ) {
@@ -56,6 +105,7 @@ export function renderToMarkup(
56
105
} ,
57
106
// $FlowFixMe[missing-local-annot]
58
107
destroy ( error ) {
108
+ abortFlight ( flightRequest , error ) ;
59
109
reject ( error ) ;
60
110
} ,
61
111
} ;
@@ -65,12 +115,33 @@ export function renderToMarkup(
65
115
// client rendering mode because there's no client rendering here.
66
116
reject ( error ) ;
67
117
}
118
+ const flightRequest = createFlightRequest (
119
+ // $FlowFixMe: This should be a subtype but not everything is typed covariant.
120
+ children ,
121
+ null ,
122
+ onError ,
123
+ options ? options . identifierPrefix : undefined ,
124
+ undefined ,
125
+ 'Markup' ,
126
+ undefined ,
127
+ ) ;
128
+ const flightResponse = createFlightResponse (
129
+ null ,
130
+ null ,
131
+ noServerCallOrFormAction ,
132
+ noServerCallOrFormAction ,
133
+ undefined ,
134
+ undefined ,
135
+ undefined ,
136
+ ) ;
68
137
const resumableState = createResumableState (
69
138
options ? options . identifierPrefix : undefined ,
70
139
undefined ,
71
140
) ;
72
- const request = createRequest (
73
- children ,
141
+ const root = getFlightRoot < ReactNodeList > ( flightResponse ) ;
142
+ const fizzRequest = createFizzRequest (
143
+ // $FlowFixMe: Thenables as children are supported.
144
+ root ,
74
145
resumableState ,
75
146
createRenderState ( resumableState , true ) ,
76
147
createRootFormatContext ( ) ,
@@ -86,17 +157,21 @@ export function renderToMarkup(
86
157
if ( options && options . signal ) {
87
158
const signal = options . signal ;
88
159
if ( signal . aborted ) {
89
- abort ( request , ( signal : any ) . reason ) ;
160
+ abortFlight ( flightRequest , ( signal : any ) . reason ) ;
161
+ abortFizz ( fizzRequest , ( signal : any ) . reason ) ;
90
162
} else {
91
163
const listener = ( ) = > {
92
- abort ( request , ( signal : any ) . reason ) ;
164
+ abortFlight ( flightRequest , ( signal : any ) . reason ) ;
165
+ abortFizz ( fizzRequest , ( signal : any ) . reason ) ;
93
166
signal . removeEventListener ( 'abort' , listener ) ;
94
167
} ;
95
168
signal . addEventListener ( 'abort' , listener ) ;
96
169
}
97
170
}
98
- startWork ( request ) ;
99
- startFlowing ( request , destination ) ;
171
+ startFlightWork ( flightRequest ) ;
172
+ startFlightFlowing ( flightRequest , flightDestination ) ;
173
+ startFizzWork ( fizzRequest ) ;
174
+ startFizzFlowing ( fizzRequest , fizzDestination ) ;
100
175
} ) ;
101
176
}
102
177
0 commit comments