@@ -24,15 +24,25 @@ import invariant from 'shared/invariant';
2424
2525// Per response,
2626export type ResponseState = {
27+ placeholderPrefix : PrecomputedChunk ,
28+ segmentPrefix : PrecomputedChunk ,
29+ boundaryPrefix : string ,
30+ opaqueIdentifierPrefix : PrecomputedChunk ,
2731 nextSuspenseID : number ,
2832 sentCompleteSegmentFunction : boolean ,
2933 sentCompleteBoundaryFunction : boolean ,
3034 sentClientRenderFunction : boolean ,
3135} ;
3236
3337// 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 {
3541 return {
42+ placeholderPrefix : stringToPrecomputedChunk ( identifierPrefix + 'P:' ) ,
43+ segmentPrefix : stringToPrecomputedChunk ( identifierPrefix + 'S:' ) ,
44+ boundaryPrefix : identifierPrefix + 'B:' ,
45+ opaqueIdentifierPrefix : stringToPrecomputedChunk ( identifierPrefix + 'R:' ) ,
3646 nextSuspenseID : 0 ,
3747 sentCompleteSegmentFunction : false ,
3848 sentCompleteBoundaryFunction : false ,
@@ -68,7 +78,7 @@ function assignAnID(
6878 // TODO: This approach doesn't yield deterministic results since this is assigned during render.
6979 const generatedID = responseState . nextSuspenseID ++ ;
7080 return ( id . formattedID = stringToPrecomputedChunk (
71- 'B:' + generatedID . toString ( 16 ) ,
81+ responseState . boundaryPrefix + generatedID . toString ( 16 ) ,
7282 ) ) ;
7383}
7484
@@ -160,20 +170,19 @@ export function pushEndInstance(
160170// A placeholder is a node inside a hidden partial tree that can be filled in later, but before
161171// display. It's never visible to users.
162172const placeholder1 = stringToPrecomputedChunk ( '<span id="' ) ;
163- const placeholder2 = stringToPrecomputedChunk ( 'P:' ) ;
164- const placeholder3 = stringToPrecomputedChunk ( '"></span>' ) ;
173+ const placeholder2 = stringToPrecomputedChunk ( '"></span>' ) ;
165174export function writePlaceholder (
166175 destination : Destination ,
176+ responseState : ResponseState ,
167177 id : number ,
168178) : boolean {
169179 // TODO: This needs to be contextually aware and switch tag since not all parents allow for spans like
170180 // <select> or <tbody>. E.g. suspending a component that renders a table row.
171181 writeChunk ( destination , placeholder1 ) ;
172- // TODO: Use the identifierPrefix option to make the prefix configurable.
173- writeChunk ( destination , placeholder2 ) ;
182+ writeChunk ( destination , responseState . placeholderPrefix ) ;
174183 const formattedID = stringToChunk ( id . toString ( 16 ) ) ;
175184 writeChunk ( destination , formattedID ) ;
176- return writeChunk ( destination , placeholder3 ) ;
185+ return writeChunk ( destination , placeholder2 ) ;
177186}
178187
179188// Suspense boundaries are encoded as comments.
@@ -207,20 +216,19 @@ export function writeEndSuspenseBoundary(destination: Destination): boolean {
207216}
208217
209218const startSegment = stringToPrecomputedChunk ( '<div hidden id="' ) ;
210- const startSegment2 = stringToPrecomputedChunk ( 'S:' ) ;
211- const startSegment3 = stringToPrecomputedChunk ( '">' ) ;
219+ const startSegment2 = stringToPrecomputedChunk ( '">' ) ;
212220const endSegment = stringToPrecomputedChunk ( '</div>' ) ;
213221export function writeStartSegment (
214222 destination : Destination ,
223+ responseState : ResponseState ,
215224 id : number ,
216225) : boolean {
217226 // TODO: What happens with special children like <tr> if they're inserted in a div? Maybe needs contextually aware containers.
218227 writeChunk ( destination , startSegment ) ;
219- // TODO: Use the identifierPrefix option to make the prefix configurable.
220- writeChunk ( destination , startSegment2 ) ;
228+ writeChunk ( destination , responseState . segmentPrefix ) ;
221229 const formattedID = stringToChunk ( id . toString ( 16 ) ) ;
222230 writeChunk ( destination , formattedID ) ;
223- return writeChunk ( destination , startSegment3 ) ;
231+ return writeChunk ( destination , startSegment2 ) ;
224232}
225233export function writeEndSegment ( destination : Destination ) : boolean {
226234 return writeChunk ( destination , endSegment ) ;
@@ -349,12 +357,10 @@ const clientRenderFunction =
349357 'function $RX(b){if(b=document.getElementById(b)){do b=b.previousSibling;while(8!==b.nodeType||"$?"!==b.data);b.data="$!";b._reactRetry&&b._reactRetry()}}' ;
350358
351359const completeSegmentScript1Full = stringToPrecomputedChunk (
352- '<script>' + completeSegmentFunction + ';$RS("S:' ,
353- ) ;
354- const completeSegmentScript1Partial = stringToPrecomputedChunk (
355- '<script>$RS("S:' ,
360+ '<script>' + completeSegmentFunction + ';$RS("' ,
356361) ;
357- const completeSegmentScript2 = stringToPrecomputedChunk ( '","P:' ) ;
362+ const completeSegmentScript1Partial = stringToPrecomputedChunk ( '<script>$RS("' ) ;
363+ const completeSegmentScript2 = stringToPrecomputedChunk ( '","' ) ;
358364const completeSegmentScript3 = stringToPrecomputedChunk ( '")</script>' ) ;
359365
360366export function writeCompletedSegmentInstruction (
@@ -370,10 +376,11 @@ export function writeCompletedSegmentInstruction(
370376 // Future calls can just reuse the same function.
371377 writeChunk ( destination , completeSegmentScript1Partial ) ;
372378 }
373- // TODO: Use the identifierPrefix option to make the prefix configurable.
379+ writeChunk ( destination , responseState . segmentPrefix ) ;
374380 const formattedID = stringToChunk ( contentSegmentID . toString ( 16 ) ) ;
375381 writeChunk ( destination , formattedID ) ;
376382 writeChunk ( destination , completeSegmentScript2 ) ;
383+ writeChunk ( destination , responseState . placeholderPrefix ) ;
377384 writeChunk ( destination , formattedID ) ;
378385 return writeChunk ( destination , completeSegmentScript3 ) ;
379386}
@@ -384,7 +391,7 @@ const completeBoundaryScript1Full = stringToPrecomputedChunk(
384391const completeBoundaryScript1Partial = stringToPrecomputedChunk (
385392 '<script>$RC("' ,
386393) ;
387- const completeBoundaryScript2 = stringToPrecomputedChunk ( '","S: ' ) ;
394+ const completeBoundaryScript2 = stringToPrecomputedChunk ( '","' ) ;
388395const completeBoundaryScript3 = stringToPrecomputedChunk ( '")</script>' ) ;
389396
390397export function writeCompletedBoundaryInstruction (
@@ -401,7 +408,6 @@ export function writeCompletedBoundaryInstruction(
401408 // Future calls can just reuse the same function.
402409 writeChunk ( destination , completeBoundaryScript1Partial ) ;
403410 }
404- // TODO: Use the identifierPrefix option to make the prefix configurable.
405411 const formattedBoundaryID = boundaryID . formattedID ;
406412 invariant (
407413 formattedBoundaryID !== null ,
@@ -410,6 +416,7 @@ export function writeCompletedBoundaryInstruction(
410416 const formattedContentID = stringToChunk ( contentSegmentID . toString ( 16 ) ) ;
411417 writeChunk ( destination , formattedBoundaryID ) ;
412418 writeChunk ( destination , completeBoundaryScript2 ) ;
419+ writeChunk ( destination , responseState . segmentPrefix ) ;
413420 writeChunk ( destination , formattedContentID ) ;
414421 return writeChunk ( destination , completeBoundaryScript3 ) ;
415422}
0 commit comments