From 6129a7f8dd933e05670888db604e46813d1748c6 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 30 Jan 2023 22:05:28 -0500 Subject: [PATCH 1/6] Change "@123" references to "$L123" These are lazy references to future values. We currently claim both $ and @ as special symbols for encoding our instructions in JSON. We don't need two, and two are not enough anyway. --- .../react-client/src/ReactFlightClient.js | 31 +++++++++++-------- .../react-server/src/ReactFlightServer.js | 4 +-- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 5293bc794af26..3d53cbfb4c251 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -483,14 +483,26 @@ export function parseModelString( key: string, value: string, ): any { - switch (value[0]) { - case '$': { - if (value === '$') { - return REACT_ELEMENT_TYPE; - } else if (value[1] === '$' || value[1] === '@') { + if (value[0] === '$') { + if (value === '$') { + // A very common symbol. + return REACT_ELEMENT_TYPE; + } + switch (value[1]) { + case '$': { // This was an escaped string value. return value.substring(1); - } else { + } + case 'L': { + // Lazy node + const id = parseInt(value.substring(2), 16); + const chunk = getChunk(response, id); + // We create a React.lazy wrapper around any lazy values. + // When passed into React, we'll know how to suspend on this. + return createLazyChunkWrapper(chunk); + } + default: { + // We assume that anything else is a reference ID. const id = parseInt(value.substring(1), 16); const chunk = getChunk(response, id); switch (chunk.status) { @@ -518,13 +530,6 @@ export function parseModelString( } } } - case '@': { - const id = parseInt(value.substring(1), 16); - const chunk = getChunk(response, id); - // We create a React.lazy wrapper around any lazy values. - // When passed into React, we'll know how to suspend on this. - return createLazyChunkWrapper(chunk); - } } return value; } diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 1d1b32f8ca49f..e78ea3b209aaf 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -417,7 +417,7 @@ function serializeByValueID(id: number): string { } function serializeByRefID(id: number): string { - return '@' + id.toString(16); + return '$L' + id.toString(16); } function serializeClientReference( @@ -473,7 +473,7 @@ function serializeClientReference( } function escapeStringValue(value: string): string { - if (value[0] === '$' || value[0] === '@') { + if (value[0] === '$') { // We need to escape $ or @ prefixed strings since we use those to encode // references to IDs and as special symbol values. return '$' + value; From 94fe68b7377406b999cb554e7525d1ce9b28aaa6 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 30 Jan 2023 22:12:41 -0500 Subject: [PATCH 2/6] Move the row tag until after the row ID. This feels a bit easier to read. --- packages/react-client/src/ReactFlightClientStream.js | 8 ++++---- .../react-server/src/ReactFlightServerConfigStream.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/react-client/src/ReactFlightClientStream.js b/packages/react-client/src/ReactFlightClientStream.js index 4709ca8085ddc..c4b2de7a49e28 100644 --- a/packages/react-client/src/ReactFlightClientStream.js +++ b/packages/react-client/src/ReactFlightClientStream.js @@ -36,14 +36,14 @@ function processFullRow(response: Response, row: string): void { if (row === '') { return; } - const tag = row[0]; + const colon = row.indexOf(':', 0); + const id = parseInt(row.substring(0, colon), 16); + const tag = row[colon + 1]; // When tags that are not text are added, check them here before // parsing the row as text. // switch (tag) { // } - const colon = row.indexOf(':', 1); - const id = parseInt(row.substring(1, colon), 16); - const text = row.substring(colon + 1); + const text = row.substring(colon + 2); switch (tag) { case 'J': { resolveModel(response, id, text); diff --git a/packages/react-server/src/ReactFlightServerConfigStream.js b/packages/react-server/src/ReactFlightServerConfigStream.js index d5e4ec6f6371a..98bcd87b2e0d6 100644 --- a/packages/react-server/src/ReactFlightServerConfigStream.js +++ b/packages/react-server/src/ReactFlightServerConfigStream.js @@ -80,7 +80,7 @@ export { const stringify = JSON.stringify; function serializeRowHeader(tag: string, id: number) { - return tag + id.toString(16) + ':'; + return id.toString(16) + ':' + tag; } export function processErrorChunkProd( From 87f0c3c192865fdcd77fd3ab0460eb35340bd095 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 30 Jan 2023 22:16:47 -0500 Subject: [PATCH 3/6] Remove the J tag and just encode JSON directly for plain models JSON always starts with a punctuator or number, so there's no conflict with the other tags. Makes the output a little smaller and easier to read. --- .../src/ReactFlightClientStream.js | 19 +++++++------------ .../src/ReactFlightDOMRelayClient.js | 2 +- .../src/ReactFlightDOMRelayProtocol.js | 2 +- .../ReactFlightDOMRelayServerHostConfig.js | 4 ++-- .../src/ReactFlightNativeRelayClient.js | 2 +- .../src/ReactFlightNativeRelayProtocol.js | 2 +- .../ReactFlightNativeRelayServerHostConfig.js | 4 ++-- .../src/ReactFlightServerConfigStream.js | 4 ++-- 8 files changed, 17 insertions(+), 22 deletions(-) diff --git a/packages/react-client/src/ReactFlightClientStream.js b/packages/react-client/src/ReactFlightClientStream.js index c4b2de7a49e28..27a6bf218d83c 100644 --- a/packages/react-client/src/ReactFlightClientStream.js +++ b/packages/react-client/src/ReactFlightClientStream.js @@ -43,26 +43,21 @@ function processFullRow(response: Response, row: string): void { // parsing the row as text. // switch (tag) { // } - const text = row.substring(colon + 2); switch (tag) { - case 'J': { - resolveModel(response, id, text); - return; - } case 'M': { - resolveModule(response, id, text); + resolveModule(response, id, row.substring(colon + 2)); return; } case 'P': { - resolveProvider(response, id, text); + resolveProvider(response, id, row.substring(colon + 2)); return; } case 'S': { - resolveSymbol(response, id, JSON.parse(text)); + resolveSymbol(response, id, JSON.parse(row.substring(colon + 2))); return; } case 'E': { - const errorInfo = JSON.parse(text); + const errorInfo = JSON.parse(row.substring(colon + 2)); if (__DEV__) { resolveErrorDev( response, @@ -77,9 +72,9 @@ function processFullRow(response: Response, row: string): void { return; } default: { - throw new Error( - "Error parsing the data. It's probably an error code or network corruption.", - ); + // We assume anything else is JSON. + resolveModel(response, id, row.substring(colon + 1)); + return; } } } diff --git a/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js b/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js index 5e344c1398c53..fc4a2de331e82 100644 --- a/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js +++ b/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js @@ -25,7 +25,7 @@ import { export {createResponse, close, getRoot}; export function resolveRow(response: Response, chunk: RowEncoding): void { - if (chunk[0] === 'J') { + if (chunk[0] === 'O') { // $FlowFixMe unable to refine on array indices resolveModel(response, chunk[1], chunk[2]); } else if (chunk[0] === 'M') { diff --git a/packages/react-server-dom-relay/src/ReactFlightDOMRelayProtocol.js b/packages/react-server-dom-relay/src/ReactFlightDOMRelayProtocol.js index 3b3425abeca06..8a28a36518b3f 100644 --- a/packages/react-server-dom-relay/src/ReactFlightDOMRelayProtocol.js +++ b/packages/react-server-dom-relay/src/ReactFlightDOMRelayProtocol.js @@ -18,7 +18,7 @@ export type JSONValue = | $ReadOnlyArray; export type RowEncoding = - | ['J', number, JSONValue] + | ['O', number, JSONValue] | ['M', number, ModuleMetaData] | ['P', number, string] | ['S', number, string] diff --git a/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js b/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js index 27fbaf25f64ad..aa18580465730 100644 --- a/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js +++ b/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js @@ -151,7 +151,7 @@ export function processModelChunk( ): Chunk { // $FlowFixMe no good way to define an empty exact object const json = convertModelToJSON(request, {}, '', model); - return ['J', id, json]; + return ['O', id, json]; } export function processReferenceChunk( @@ -159,7 +159,7 @@ export function processReferenceChunk( id: number, reference: string, ): Chunk { - return ['J', id, reference]; + return ['O', id, reference]; } export function processModuleChunk( diff --git a/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js b/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js index 94f287971441f..a47ba7c7ba1f9 100644 --- a/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js +++ b/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js @@ -25,7 +25,7 @@ import { export {createResponse, close, getRoot}; export function resolveRow(response: Response, chunk: RowEncoding): void { - if (chunk[0] === 'J') { + if (chunk[0] === 'O') { // $FlowFixMe `Chunk` doesn't flow into `JSONValue` because of the `E` row type. resolveModel(response, chunk[1], chunk[2]); } else if (chunk[0] === 'M') { diff --git a/packages/react-server-native-relay/src/ReactFlightNativeRelayProtocol.js b/packages/react-server-native-relay/src/ReactFlightNativeRelayProtocol.js index a69b14407aec1..c8c1c6f3d257a 100644 --- a/packages/react-server-native-relay/src/ReactFlightNativeRelayProtocol.js +++ b/packages/react-server-native-relay/src/ReactFlightNativeRelayProtocol.js @@ -18,7 +18,7 @@ export type JSONValue = | Array; export type RowEncoding = - | ['J', number, JSONValue] + | ['O', number, JSONValue] | ['M', number, ModuleMetaData] | ['P', number, string] | ['S', number, string] diff --git a/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js b/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js index 552b37913819b..2f7f3bff2c68f 100644 --- a/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js +++ b/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js @@ -146,7 +146,7 @@ export function processModelChunk( ): Chunk { // $FlowFixMe no good way to define an empty exact object const json = convertModelToJSON(request, {}, '', model); - return ['J', id, json]; + return ['O', id, json]; } export function processReferenceChunk( @@ -154,7 +154,7 @@ export function processReferenceChunk( id: number, reference: string, ): Chunk { - return ['J', id, reference]; + return ['O', id, reference]; } export function processModuleChunk( diff --git a/packages/react-server/src/ReactFlightServerConfigStream.js b/packages/react-server/src/ReactFlightServerConfigStream.js index 98bcd87b2e0d6..5c7146d4ccdea 100644 --- a/packages/react-server/src/ReactFlightServerConfigStream.js +++ b/packages/react-server/src/ReactFlightServerConfigStream.js @@ -127,7 +127,7 @@ export function processModelChunk( model: ReactModel, ): Chunk { const json: string = stringify(model, request.toJSON); - const row = serializeRowHeader('J', id) + json + '\n'; + const row = id.toString(16) + ':' + json + '\n'; return stringToChunk(row); } @@ -137,7 +137,7 @@ export function processReferenceChunk( reference: string, ): Chunk { const json = stringify(reference); - const row = serializeRowHeader('J', id) + json + '\n'; + const row = id.toString(16) + ':' + json + '\n'; return stringToChunk(row); } From de91c08af823d45a58dcc78940d6e53e9c61c7d1 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 30 Jan 2023 22:20:40 -0500 Subject: [PATCH 4/6] Rename M module tag to I for import This frees up the M up for Maps. --- packages/react-client/src/ReactFlightClientStream.js | 2 +- .../react-server-dom-relay/src/ReactFlightDOMRelayClient.js | 2 +- .../react-server-dom-relay/src/ReactFlightDOMRelayProtocol.js | 2 +- .../src/ReactFlightDOMRelayServerHostConfig.js | 2 +- .../src/ReactFlightNativeRelayClient.js | 2 +- .../src/ReactFlightNativeRelayProtocol.js | 2 +- .../src/ReactFlightNativeRelayServerHostConfig.js | 2 +- packages/react-server/src/ReactFlightServerConfigStream.js | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/react-client/src/ReactFlightClientStream.js b/packages/react-client/src/ReactFlightClientStream.js index 27a6bf218d83c..992f53094dead 100644 --- a/packages/react-client/src/ReactFlightClientStream.js +++ b/packages/react-client/src/ReactFlightClientStream.js @@ -44,7 +44,7 @@ function processFullRow(response: Response, row: string): void { // switch (tag) { // } switch (tag) { - case 'M': { + case 'I': { resolveModule(response, id, row.substring(colon + 2)); return; } diff --git a/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js b/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js index fc4a2de331e82..b1ccb4b395ede 100644 --- a/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js +++ b/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js @@ -28,7 +28,7 @@ export function resolveRow(response: Response, chunk: RowEncoding): void { if (chunk[0] === 'O') { // $FlowFixMe unable to refine on array indices resolveModel(response, chunk[1], chunk[2]); - } else if (chunk[0] === 'M') { + } else if (chunk[0] === 'I') { // $FlowFixMe unable to refine on array indices resolveModule(response, chunk[1], chunk[2]); } else if (chunk[0] === 'S') { diff --git a/packages/react-server-dom-relay/src/ReactFlightDOMRelayProtocol.js b/packages/react-server-dom-relay/src/ReactFlightDOMRelayProtocol.js index 8a28a36518b3f..f770432dce1e2 100644 --- a/packages/react-server-dom-relay/src/ReactFlightDOMRelayProtocol.js +++ b/packages/react-server-dom-relay/src/ReactFlightDOMRelayProtocol.js @@ -19,7 +19,7 @@ export type JSONValue = export type RowEncoding = | ['O', number, JSONValue] - | ['M', number, ModuleMetaData] + | ['I', number, ModuleMetaData] | ['P', number, string] | ['S', number, string] | [ diff --git a/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js b/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js index aa18580465730..c132cefc422d9 100644 --- a/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js +++ b/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js @@ -168,7 +168,7 @@ export function processModuleChunk( moduleMetaData: ModuleMetaData, ): Chunk { // The moduleMetaData is already a JSON serializable value. - return ['M', id, moduleMetaData]; + return ['I', id, moduleMetaData]; } export function processProviderChunk( diff --git a/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js b/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js index a47ba7c7ba1f9..4d0dd38a8ab63 100644 --- a/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js +++ b/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js @@ -28,7 +28,7 @@ export function resolveRow(response: Response, chunk: RowEncoding): void { if (chunk[0] === 'O') { // $FlowFixMe `Chunk` doesn't flow into `JSONValue` because of the `E` row type. resolveModel(response, chunk[1], chunk[2]); - } else if (chunk[0] === 'M') { + } else if (chunk[0] === 'I') { // $FlowFixMe `Chunk` doesn't flow into `JSONValue` because of the `E` row type. resolveModule(response, chunk[1], chunk[2]); } else if (chunk[0] === 'S') { diff --git a/packages/react-server-native-relay/src/ReactFlightNativeRelayProtocol.js b/packages/react-server-native-relay/src/ReactFlightNativeRelayProtocol.js index c8c1c6f3d257a..788fd14293ca3 100644 --- a/packages/react-server-native-relay/src/ReactFlightNativeRelayProtocol.js +++ b/packages/react-server-native-relay/src/ReactFlightNativeRelayProtocol.js @@ -19,7 +19,7 @@ export type JSONValue = export type RowEncoding = | ['O', number, JSONValue] - | ['M', number, ModuleMetaData] + | ['I', number, ModuleMetaData] | ['P', number, string] | ['S', number, string] | [ diff --git a/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js b/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js index 2f7f3bff2c68f..6432e17ba795f 100644 --- a/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js +++ b/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js @@ -163,7 +163,7 @@ export function processModuleChunk( moduleMetaData: ModuleMetaData, ): Chunk { // The moduleMetaData is already a JSON serializable value. - return ['M', id, moduleMetaData]; + return ['I', id, moduleMetaData]; } export function processProviderChunk( diff --git a/packages/react-server/src/ReactFlightServerConfigStream.js b/packages/react-server/src/ReactFlightServerConfigStream.js index 5c7146d4ccdea..f919873a7e449 100644 --- a/packages/react-server/src/ReactFlightServerConfigStream.js +++ b/packages/react-server/src/ReactFlightServerConfigStream.js @@ -147,7 +147,7 @@ export function processModuleChunk( moduleMetaData: ReactModel, ): Chunk { const json: string = stringify(moduleMetaData); - const row = serializeRowHeader('M', id) + json + '\n'; + const row = serializeRowHeader('I', id) + json + '\n'; return stringToChunk(row); } From d407b90635e9ddcc89245893d6aafe9bfbf9ea1f Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 30 Jan 2023 22:35:40 -0500 Subject: [PATCH 5/6] Serialize Symbols as an inline JSON string instead of special row The serialization still emits it as a separate row since it's likely to be reused later. --- packages/react-client/src/ReactFlightClient.js | 14 +++----------- .../react-client/src/ReactFlightClientStream.js | 5 ----- .../src/ReactFlightDOMRelayClient.js | 4 ---- .../src/ReactFlightDOMRelayServerHostConfig.js | 8 -------- .../src/ReactFlightNativeRelayClient.js | 4 ---- .../src/ReactFlightNativeRelayServerHostConfig.js | 8 -------- packages/react-server/src/ReactFlightServer.js | 8 ++++++-- .../src/ReactFlightServerConfigStream.js | 10 ---------- 8 files changed, 9 insertions(+), 52 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 3d53cbfb4c251..d7eb164b13520 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -501,6 +501,9 @@ export function parseModelString( // When passed into React, we'll know how to suspend on this. return createLazyChunkWrapper(chunk); } + case 'S': { + return Symbol.for(value.substring(2)); + } default: { // We assume that anything else is a reference ID. const id = parseInt(value.substring(1), 16); @@ -631,17 +634,6 @@ export function resolveModule( } } -export function resolveSymbol( - response: Response, - id: number, - name: string, -): void { - const chunks = response._chunks; - // We assume that we'll always emit the symbol before anything references it - // to save a few bytes. - chunks.set(id, createInitializedChunk(response, Symbol.for(name))); -} - type ErrorWithDigest = Error & {digest?: string}; export function resolveErrorProd( response: Response, diff --git a/packages/react-client/src/ReactFlightClientStream.js b/packages/react-client/src/ReactFlightClientStream.js index 992f53094dead..df88131d6d2c7 100644 --- a/packages/react-client/src/ReactFlightClientStream.js +++ b/packages/react-client/src/ReactFlightClientStream.js @@ -15,7 +15,6 @@ import { resolveModule, resolveModel, resolveProvider, - resolveSymbol, resolveErrorProd, resolveErrorDev, createResponse as createResponseBase, @@ -52,10 +51,6 @@ function processFullRow(response: Response, row: string): void { resolveProvider(response, id, row.substring(colon + 2)); return; } - case 'S': { - resolveSymbol(response, id, JSON.parse(row.substring(colon + 2))); - return; - } case 'E': { const errorInfo = JSON.parse(row.substring(colon + 2)); if (__DEV__) { diff --git a/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js b/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js index b1ccb4b395ede..5bf775bfb5f26 100644 --- a/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js +++ b/packages/react-server-dom-relay/src/ReactFlightDOMRelayClient.js @@ -15,7 +15,6 @@ import { createResponse, resolveModel, resolveModule, - resolveSymbol, resolveErrorDev, resolveErrorProd, close, @@ -31,9 +30,6 @@ export function resolveRow(response: Response, chunk: RowEncoding): void { } else if (chunk[0] === 'I') { // $FlowFixMe unable to refine on array indices resolveModule(response, chunk[1], chunk[2]); - } else if (chunk[0] === 'S') { - // $FlowFixMe: Flow doesn't support disjoint unions on tuples. - resolveSymbol(response, chunk[1], chunk[2]); } else { if (__DEV__) { resolveErrorDev( diff --git a/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js b/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js index c132cefc422d9..b26321ec179c3 100644 --- a/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js +++ b/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js @@ -179,14 +179,6 @@ export function processProviderChunk( return ['P', id, contextName]; } -export function processSymbolChunk( - request: Request, - id: number, - name: string, -): Chunk { - return ['S', id, name]; -} - export function scheduleWork(callback: () => void) { callback(); } diff --git a/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js b/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js index 4d0dd38a8ab63..b9a398cc9328b 100644 --- a/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js +++ b/packages/react-server-native-relay/src/ReactFlightNativeRelayClient.js @@ -15,7 +15,6 @@ import { createResponse, resolveModel, resolveModule, - resolveSymbol, resolveErrorDev, resolveErrorProd, close, @@ -31,9 +30,6 @@ export function resolveRow(response: Response, chunk: RowEncoding): void { } else if (chunk[0] === 'I') { // $FlowFixMe `Chunk` doesn't flow into `JSONValue` because of the `E` row type. resolveModule(response, chunk[1], chunk[2]); - } else if (chunk[0] === 'S') { - // $FlowFixMe: Flow doesn't support disjoint unions on tuples. - resolveSymbol(response, chunk[1], chunk[2]); } else { if (__DEV__) { resolveErrorDev( diff --git a/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js b/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js index 6432e17ba795f..96f04788f5e40 100644 --- a/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js +++ b/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js @@ -174,14 +174,6 @@ export function processProviderChunk( return ['P', id, contextName]; } -export function processSymbolChunk( - request: Request, - id: number, - name: string, -): Chunk { - return ['S', id, name]; -} - export function scheduleWork(callback: () => void) { callback(); } diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index e78ea3b209aaf..085a1a59d27e3 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -39,7 +39,6 @@ import { processModelChunk, processModuleChunk, processProviderChunk, - processSymbolChunk, processErrorChunkProd, processErrorChunkDev, processReferenceChunk, @@ -420,6 +419,10 @@ function serializeByRefID(id: number): string { return '$L' + id.toString(16); } +function serializeSymbolReference(name: string): string { + return '$S' + name; +} + function serializeClientReference( request: Request, parent: {+[key: string | number]: ReactModel} | $ReadOnlyArray, @@ -1109,7 +1112,8 @@ function emitModuleChunk( } function emitSymbolChunk(request: Request, id: number, name: string): void { - const processedChunk = processSymbolChunk(request, id, name); + const symbolReference = serializeSymbolReference(name); + const processedChunk = processReferenceChunk(request, id, symbolReference); request.completedModuleChunks.push(processedChunk); } diff --git a/packages/react-server/src/ReactFlightServerConfigStream.js b/packages/react-server/src/ReactFlightServerConfigStream.js index f919873a7e449..42f76d8e4573c 100644 --- a/packages/react-server/src/ReactFlightServerConfigStream.js +++ b/packages/react-server/src/ReactFlightServerConfigStream.js @@ -160,16 +160,6 @@ export function processProviderChunk( return stringToChunk(row); } -export function processSymbolChunk( - request: Request, - id: number, - name: string, -): Chunk { - const json = stringify(name); - const row = serializeRowHeader('S', id) + json + '\n'; - return stringToChunk(row); -} - export { scheduleWork, flushBuffered, From 70963f8272d74d6f52bb70293d98b8452d48b041 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 30 Jan 2023 22:41:28 -0500 Subject: [PATCH 6/6] Serialize Provider as an inline JSON string instead of special row We still emit it as a separate row in case it's reused but it's not needed. --- .../react-client/src/ReactFlightClient.js | 26 +++---------------- .../src/ReactFlightClientStream.js | 5 ---- .../ReactFlightDOMRelayServerHostConfig.js | 8 ------ .../ReactFlightNativeRelayServerHostConfig.js | 8 ------ .../react-server/src/ReactFlightServer.js | 8 ++++-- .../src/ReactFlightServerConfigStream.js | 9 ------- 6 files changed, 9 insertions(+), 55 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index d7eb164b13520..38d0c7b1c5b68 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -201,14 +201,6 @@ function createErrorChunk( return new Chunk(ERRORED, null, error, response); } -function createInitializedChunk( - response: Response, - value: T, -): InitializedChunk { - // $FlowFixMe Flow doesn't support functions as constructors - return new Chunk(INITIALIZED, value, null, response); -} - function wakeChunk(listeners: Array<(T) => mixed>, value: T): void { for (let i = 0; i < listeners.length; i++) { const listener = listeners[i]; @@ -504,6 +496,9 @@ export function parseModelString( case 'S': { return Symbol.for(value.substring(2)); } + case 'P': { + return getOrCreateServerContext(value.substring(2)).Provider; + } default: { // We assume that anything else is a reference ID. const id = parseInt(value.substring(1), 16); @@ -574,21 +569,6 @@ export function resolveModel( } } -export function resolveProvider( - response: Response, - id: number, - contextName: string, -): void { - const chunks = response._chunks; - chunks.set( - id, - createInitializedChunk( - response, - getOrCreateServerContext(contextName).Provider, - ), - ); -} - export function resolveModule( response: Response, id: number, diff --git a/packages/react-client/src/ReactFlightClientStream.js b/packages/react-client/src/ReactFlightClientStream.js index df88131d6d2c7..79ed3b1c9cf17 100644 --- a/packages/react-client/src/ReactFlightClientStream.js +++ b/packages/react-client/src/ReactFlightClientStream.js @@ -14,7 +14,6 @@ import type {BundlerConfig} from './ReactFlightClientHostConfig'; import { resolveModule, resolveModel, - resolveProvider, resolveErrorProd, resolveErrorDev, createResponse as createResponseBase, @@ -47,10 +46,6 @@ function processFullRow(response: Response, row: string): void { resolveModule(response, id, row.substring(colon + 2)); return; } - case 'P': { - resolveProvider(response, id, row.substring(colon + 2)); - return; - } case 'E': { const errorInfo = JSON.parse(row.substring(colon + 2)); if (__DEV__) { diff --git a/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js b/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js index b26321ec179c3..bc5a321622ede 100644 --- a/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js +++ b/packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js @@ -171,14 +171,6 @@ export function processModuleChunk( return ['I', id, moduleMetaData]; } -export function processProviderChunk( - request: Request, - id: number, - contextName: string, -): Chunk { - return ['P', id, contextName]; -} - export function scheduleWork(callback: () => void) { callback(); } diff --git a/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js b/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js index 96f04788f5e40..d005ccbdf1e6d 100644 --- a/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js +++ b/packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js @@ -166,14 +166,6 @@ export function processModuleChunk( return ['I', id, moduleMetaData]; } -export function processProviderChunk( - request: Request, - id: number, - contextName: string, -): Chunk { - return ['P', id, contextName]; -} - export function scheduleWork(callback: () => void) { callback(); } diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 085a1a59d27e3..af90377e53227 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -38,7 +38,6 @@ import { closeWithError, processModelChunk, processModuleChunk, - processProviderChunk, processErrorChunkProd, processErrorChunkDev, processReferenceChunk, @@ -423,6 +422,10 @@ function serializeSymbolReference(name: string): string { return '$S' + name; } +function serializeProviderReference(name: string): string { + return '$P' + name; +} + function serializeClientReference( request: Request, parent: {+[key: string | number]: ReactModel} | $ReadOnlyArray, @@ -1122,7 +1125,8 @@ function emitProviderChunk( id: number, contextName: string, ): void { - const processedChunk = processProviderChunk(request, id, contextName); + const contextReference = serializeProviderReference(contextName); + const processedChunk = processReferenceChunk(request, id, contextReference); request.completedJSONChunks.push(processedChunk); } diff --git a/packages/react-server/src/ReactFlightServerConfigStream.js b/packages/react-server/src/ReactFlightServerConfigStream.js index 42f76d8e4573c..7364ab86dbfb7 100644 --- a/packages/react-server/src/ReactFlightServerConfigStream.js +++ b/packages/react-server/src/ReactFlightServerConfigStream.js @@ -151,15 +151,6 @@ export function processModuleChunk( return stringToChunk(row); } -export function processProviderChunk( - request: Request, - id: number, - contextName: string, -): Chunk { - const row = serializeRowHeader('P', id) + contextName + '\n'; - return stringToChunk(row); -} - export { scheduleWork, flushBuffered,