Skip to content

Commit

Permalink
Move lazy ID initialization to the core implementation
Browse files Browse the repository at this point in the history
We never need an ID before we write a pending boundary. This also ensures
that ID generation is deterministic by moving it to the write phase.
  • Loading branch information
sebmarkbage committed Sep 24, 2021
1 parent da90f16 commit b1f53b1
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 36 deletions.
40 changes: 17 additions & 23 deletions packages/react-dom/src/server/ReactDOMServerFormatConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,17 @@ export function getChildFormatContext(
return parentContext;
}

export type SuspenseBoundaryID = {
formattedID: null | PrecomputedChunk,
};
export type SuspenseBoundaryID = null | PrecomputedChunk;

export const UNINITIALIZED_SUSPENSE_BOUNDARY_ID: SuspenseBoundaryID = null;

export function createSuspenseBoundaryID(
export function assignSuspenseBoundaryID(
responseState: ResponseState,
): SuspenseBoundaryID {
return {formattedID: null};
const generatedID = responseState.nextSuspenseID++;
return stringToPrecomputedChunk(
responseState.boundaryPrefix + generatedID.toString(16),
);
}

export type OpaqueIDType = string;
Expand All @@ -198,16 +201,6 @@ function encodeHTMLTextNode(text: string): string {
return escapeTextForBrowser(text);
}

function assignAnID(
responseState: ResponseState,
id: SuspenseBoundaryID,
): PrecomputedChunk {
const generatedID = responseState.nextSuspenseID++;
return (id.formattedID = stringToPrecomputedChunk(
responseState.boundaryPrefix + generatedID.toString(16),
));
}

const textSeparator = stringToPrecomputedChunk('<!-- -->');

export function pushTextInstance(
Expand Down Expand Up @@ -1377,8 +1370,11 @@ export function writeStartPendingSuspenseBoundary(
id: SuspenseBoundaryID,
): boolean {
writeChunk(destination, startPendingSuspenseBoundary1);
const formattedID = assignAnID(responseState, id);
writeChunk(destination, formattedID);
invariant(
id !== null,
'An ID must have been assigned before we can complete the boundary.',
);
writeChunk(destination, id);
return writeChunk(destination, startPendingSuspenseBoundary2);
}
export function writeStartClientRenderedSuspenseBoundary(
Expand Down Expand Up @@ -1708,13 +1704,12 @@ export function writeCompletedBoundaryInstruction(
// Future calls can just reuse the same function.
writeChunk(destination, completeBoundaryScript1Partial);
}
const formattedBoundaryID = boundaryID.formattedID;
invariant(
formattedBoundaryID !== null,
boundaryID !== null,
'An ID must have been assigned before we can complete the boundary.',
);
const formattedContentID = stringToChunk(contentSegmentID.toString(16));
writeChunk(destination, formattedBoundaryID);
writeChunk(destination, boundaryID);
writeChunk(destination, completeBoundaryScript2);
writeChunk(destination, responseState.segmentPrefix);
writeChunk(destination, formattedContentID);
Expand All @@ -1740,11 +1735,10 @@ export function writeClientRenderBoundaryInstruction(
// Future calls can just reuse the same function.
writeChunk(destination, clientRenderScript1Partial);
}
const formattedBoundaryID = boundaryID.formattedID;
invariant(
formattedBoundaryID !== null,
boundaryID !== null,
'An ID must have been assigned before we can complete the boundary.',
);
writeChunk(destination, formattedBoundaryID);
writeChunk(destination, boundaryID);
return writeChunk(destination, clientRenderScript2);
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ export type {

export {
getChildFormatContext,
createSuspenseBoundaryID,
UNINITIALIZED_SUSPENSE_BOUNDARY_ID,
assignSuspenseBoundaryID,
makeServerID,
pushStartInstance,
pushEndInstance,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,9 @@ export function getChildFormatContext(
// This is very specific to DOM where we can't assign an ID to.
export type SuspenseBoundaryID = number;

export function createSuspenseBoundaryID(
export function assignSuspenseBoundaryID(
responseState: ResponseState,
): SuspenseBoundaryID {
// TODO: This is not deterministic since it's created during render.
return responseState.nextSuspenseID++;
}

Expand Down
4 changes: 3 additions & 1 deletion packages/react-noop-renderer/src/ReactNoopServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ const ReactNoopServer = ReactFizzServer({
closeWithError(destination: Destination, error: mixed): void {},
flushBuffered(destination: Destination): void {},

createSuspenseBoundaryID(): SuspenseInstance {
UNINITIALIZED_SUSPENSE_BOUNDARY_ID: null,

assignSuspenseBoundaryID(): SuspenseInstance {
// The ID is a pointer to the boundary itself.
return {state: 'pending', children: []};
},
Expand Down
16 changes: 8 additions & 8 deletions packages/react-server/src/ReactFizzServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ import {
pushEndInstance,
pushStartCompletedSuspenseBoundary,
pushEndCompletedSuspenseBoundary,
createSuspenseBoundaryID,
UNINITIALIZED_SUSPENSE_BOUNDARY_ID,
assignSuspenseBoundaryID,
getChildFormatContext,
} from './ReactServerFormatConfig';
import {
Expand Down Expand Up @@ -123,7 +124,7 @@ type LegacyContext = {
};

type SuspenseBoundary = {
+id: SuspenseBoundaryID,
id: SuspenseBoundaryID,
rootSegmentID: number,
forceClientRender: boolean, // if it errors or infinitely suspends
parentFlushed: boolean,
Expand Down Expand Up @@ -281,7 +282,7 @@ function createSuspenseBoundary(
fallbackAbortableTasks: Set<Task>,
): SuspenseBoundary {
return {
id: createSuspenseBoundaryID(request.responseState),
id: UNINITIALIZED_SUSPENSE_BOUNDARY_ID,
rootSegmentID: -1,
parentFlushed: false,
pendingTasks: 0,
Expand Down Expand Up @@ -1595,11 +1596,10 @@ function flushSegment(
request.partialBoundaries.push(boundary);
}

writeStartPendingSuspenseBoundary(
destination,
request.responseState,
boundary.id,
);
/// This is the first time we should have referenced this ID.
const id = (boundary.id = assignSuspenseBoundaryID(request.responseState));

writeStartPendingSuspenseBoundary(destination, request.responseState, id);

// Flush the fallback.
flushSubtree(request, destination, segment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export opaque type OpaqueIDType = mixed;
export const isPrimaryRenderer = false;

export const getChildFormatContext = $$$hostConfig.getChildFormatContext;
export const createSuspenseBoundaryID = $$$hostConfig.createSuspenseBoundaryID;
export const UNINITIALIZED_SUSPENSE_BOUNDARY_ID =
$$$hostConfig.UNINITIALIZED_SUSPENSE_BOUNDARY_ID;
export const assignSuspenseBoundaryID = $$$hostConfig.assignSuspenseBoundaryID;
export const makeServerID = $$$hostConfig.makeServerID;
export const pushTextInstance = $$$hostConfig.pushTextInstance;
export const pushStartInstance = $$$hostConfig.pushStartInstance;
Expand Down

0 comments on commit b1f53b1

Please sign in to comment.