@@ -24,15 +24,25 @@ import invariant from 'shared/invariant';
24
24
25
25
// Per response,
26
26
export type ResponseState = {
27
+ placeholderPrefix : PrecomputedChunk ,
28
+ segmentPrefix : PrecomputedChunk ,
29
+ boundaryPrefix : string ,
30
+ opaqueIdentifierPrefix : PrecomputedChunk ,
27
31
nextSuspenseID : number ,
28
32
sentCompleteSegmentFunction : boolean ,
29
33
sentCompleteBoundaryFunction : boolean ,
30
34
sentClientRenderFunction : boolean ,
31
35
} ;
32
36
33
37
// Allows us to keep track of what we've already written so we can refer back to it.
34
- export function createResponseState ( ) : ResponseState {
38
+ export function createResponseState (
39
+ identifierPrefix : string = '' ,
40
+ ) : ResponseState {
35
41
return {
42
+ placeholderPrefix : stringToPrecomputedChunk ( identifierPrefix + 'P:' ) ,
43
+ segmentPrefix : stringToPrecomputedChunk ( identifierPrefix + 'S:' ) ,
44
+ boundaryPrefix : identifierPrefix + 'B:' ,
45
+ opaqueIdentifierPrefix : stringToPrecomputedChunk ( identifierPrefix + 'R:' ) ,
36
46
nextSuspenseID : 0 ,
37
47
sentCompleteSegmentFunction : false ,
38
48
sentCompleteBoundaryFunction : false ,
@@ -68,7 +78,7 @@ function assignAnID(
68
78
// TODO: This approach doesn't yield deterministic results since this is assigned during render.
69
79
const generatedID = responseState . nextSuspenseID ++ ;
70
80
return ( id . formattedID = stringToPrecomputedChunk (
71
- 'B:' + generatedID . toString ( 16 ) ,
81
+ responseState . boundaryPrefix + generatedID . toString ( 16 ) ,
72
82
) ) ;
73
83
}
74
84
@@ -160,20 +170,19 @@ export function pushEndInstance(
160
170
// A placeholder is a node inside a hidden partial tree that can be filled in later, but before
161
171
// display. It's never visible to users.
162
172
const placeholder1 = stringToPrecomputedChunk ( '<span id="' ) ;
163
- const placeholder2 = stringToPrecomputedChunk ( 'P:' ) ;
164
- const placeholder3 = stringToPrecomputedChunk ( '"></span>' ) ;
173
+ const placeholder2 = stringToPrecomputedChunk ( '"></span>' ) ;
165
174
export function writePlaceholder (
166
175
destination : Destination ,
176
+ responseState : ResponseState ,
167
177
id : number ,
168
178
) : boolean {
169
179
// TODO: This needs to be contextually aware and switch tag since not all parents allow for spans like
170
180
// <select> or <tbody>. E.g. suspending a component that renders a table row.
171
181
writeChunk ( destination , placeholder1 ) ;
172
- // TODO: Use the identifierPrefix option to make the prefix configurable.
173
- writeChunk ( destination , placeholder2 ) ;
182
+ writeChunk ( destination , responseState . placeholderPrefix ) ;
174
183
const formattedID = stringToChunk ( id . toString ( 16 ) ) ;
175
184
writeChunk ( destination , formattedID ) ;
176
- return writeChunk ( destination , placeholder3 ) ;
185
+ return writeChunk ( destination , placeholder2 ) ;
177
186
}
178
187
179
188
// Suspense boundaries are encoded as comments.
@@ -207,20 +216,19 @@ export function writeEndSuspenseBoundary(destination: Destination): boolean {
207
216
}
208
217
209
218
const startSegment = stringToPrecomputedChunk ( '<div hidden id="' ) ;
210
- const startSegment2 = stringToPrecomputedChunk ( 'S:' ) ;
211
- const startSegment3 = stringToPrecomputedChunk ( '">' ) ;
219
+ const startSegment2 = stringToPrecomputedChunk ( '">' ) ;
212
220
const endSegment = stringToPrecomputedChunk ( '</div>' ) ;
213
221
export function writeStartSegment (
214
222
destination : Destination ,
223
+ responseState : ResponseState ,
215
224
id : number ,
216
225
) : boolean {
217
226
// TODO: What happens with special children like <tr> if they're inserted in a div? Maybe needs contextually aware containers.
218
227
writeChunk ( destination , startSegment ) ;
219
- // TODO: Use the identifierPrefix option to make the prefix configurable.
220
- writeChunk ( destination , startSegment2 ) ;
228
+ writeChunk ( destination , responseState . segmentPrefix ) ;
221
229
const formattedID = stringToChunk ( id . toString ( 16 ) ) ;
222
230
writeChunk ( destination , formattedID ) ;
223
- return writeChunk ( destination , startSegment3 ) ;
231
+ return writeChunk ( destination , startSegment2 ) ;
224
232
}
225
233
export function writeEndSegment ( destination : Destination ) : boolean {
226
234
return writeChunk ( destination , endSegment ) ;
@@ -349,12 +357,10 @@ const clientRenderFunction =
349
357
'function $RX(b){if(b=document.getElementById(b)){do b=b.previousSibling;while(8!==b.nodeType||"$?"!==b.data);b.data="$!";b._reactRetry&&b._reactRetry()}}' ;
350
358
351
359
const completeSegmentScript1Full = stringToPrecomputedChunk (
352
- '<script>' + completeSegmentFunction + ';$RS("S:' ,
353
- ) ;
354
- const completeSegmentScript1Partial = stringToPrecomputedChunk (
355
- '<script>$RS("S:' ,
360
+ '<script>' + completeSegmentFunction + ';$RS("' ,
356
361
) ;
357
- const completeSegmentScript2 = stringToPrecomputedChunk ( '","P:' ) ;
362
+ const completeSegmentScript1Partial = stringToPrecomputedChunk ( '<script>$RS("' ) ;
363
+ const completeSegmentScript2 = stringToPrecomputedChunk ( '","' ) ;
358
364
const completeSegmentScript3 = stringToPrecomputedChunk ( '")</script>' ) ;
359
365
360
366
export function writeCompletedSegmentInstruction (
@@ -370,10 +376,11 @@ export function writeCompletedSegmentInstruction(
370
376
// Future calls can just reuse the same function.
371
377
writeChunk ( destination , completeSegmentScript1Partial ) ;
372
378
}
373
- // TODO: Use the identifierPrefix option to make the prefix configurable.
379
+ writeChunk ( destination , responseState . segmentPrefix ) ;
374
380
const formattedID = stringToChunk ( contentSegmentID . toString ( 16 ) ) ;
375
381
writeChunk ( destination , formattedID ) ;
376
382
writeChunk ( destination , completeSegmentScript2 ) ;
383
+ writeChunk ( destination , responseState . placeholderPrefix ) ;
377
384
writeChunk ( destination , formattedID ) ;
378
385
return writeChunk ( destination , completeSegmentScript3 ) ;
379
386
}
@@ -384,7 +391,7 @@ const completeBoundaryScript1Full = stringToPrecomputedChunk(
384
391
const completeBoundaryScript1Partial = stringToPrecomputedChunk (
385
392
'<script>$RC("' ,
386
393
) ;
387
- const completeBoundaryScript2 = stringToPrecomputedChunk ( '","S: ' ) ;
394
+ const completeBoundaryScript2 = stringToPrecomputedChunk ( '","' ) ;
388
395
const completeBoundaryScript3 = stringToPrecomputedChunk ( '")</script>' ) ;
389
396
390
397
export function writeCompletedBoundaryInstruction (
@@ -401,7 +408,6 @@ export function writeCompletedBoundaryInstruction(
401
408
// Future calls can just reuse the same function.
402
409
writeChunk ( destination , completeBoundaryScript1Partial ) ;
403
410
}
404
- // TODO: Use the identifierPrefix option to make the prefix configurable.
405
411
const formattedBoundaryID = boundaryID . formattedID ;
406
412
invariant (
407
413
formattedBoundaryID !== null ,
@@ -410,6 +416,7 @@ export function writeCompletedBoundaryInstruction(
410
416
const formattedContentID = stringToChunk ( contentSegmentID . toString ( 16 ) ) ;
411
417
writeChunk ( destination , formattedBoundaryID ) ;
412
418
writeChunk ( destination , completeBoundaryScript2 ) ;
419
+ writeChunk ( destination , responseState . segmentPrefix ) ;
413
420
writeChunk ( destination , formattedContentID ) ;
414
421
return writeChunk ( destination , completeBoundaryScript3 ) ;
415
422
}
0 commit comments