Skip to content

Commit

Permalink
Remove Flight Relay DOM/Native (#26828)
Browse files Browse the repository at this point in the history
The bindings upstream in Relay has been removed so we don't need these
builds anymore. The idea is to revisit an FB integration of Flight but
it wouldn't use the Relay specific bindings. It's a bit unclear how it
would look but likely more like the OSS version so not worth keeping
these around.

The `dom-relay` name also included the FB specific Fizz implementation
of the streaming config so I renamed that to `dom-fb`. There's no Fizz
implementation for Native yet so I just removed `native-relay`.

We created a configurable fork for how to encode the output of Flight
and the Relay implementation encoded it as JSON objects instead of
strings/streams. The new implementation would likely be more stream-like
and just encode it directly as string/binary chunks. So I removed those
indirections so that this can just be declared inline in
ReactFlightServer/Client.
  • Loading branch information
sebmarkbage authored May 18, 2023
1 parent d7a98a5 commit 5309f10
Show file tree
Hide file tree
Showing 72 changed files with 294 additions and 2,620 deletions.
1 change: 0 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,6 @@ module.exports = {
{
files: [
'packages/react-native-renderer/**/*.js',
'packages/react-server-native-relay/**/*.js',
],
globals: {
nativeFabricUIManager: 'readonly',
Expand Down
2 changes: 1 addition & 1 deletion packages/react-client/flight.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
* @flow
*/

export * from './src/ReactFlightClientStream';
export * from './src/ReactFlightClient';
143 changes: 127 additions & 16 deletions packages/react-client/src/ReactFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ import type {LazyComponent} from 'react/src/ReactLazy';
import type {
ClientReference,
ClientReferenceMetadata,
UninitializedModel,
Response,
SSRManifest,
StringDecoder,
} from './ReactFlightClientConfig';

import type {HintModel} from 'react-server/src/ReactFlightServerConfig';
Expand All @@ -26,8 +25,11 @@ import {
resolveClientReference,
preloadModule,
requireModule,
parseModel,
dispatchHint,
readPartialStringChunk,
readFinalStringChunk,
supportsBinaryStreams,
createStringDecoder,
} from './ReactFlightClientConfig';

import {
Expand All @@ -41,6 +43,8 @@ import {getOrCreateServerContext} from 'shared/ReactServerContextRegistry';

export type {CallServerCallback};

type UninitializedModel = string;

export type JSONValue =
| number
| null
Expand Down Expand Up @@ -158,15 +162,15 @@ Chunk.prototype.then = function <T>(
}
};

export type ResponseBase = {
export type Response = {
_bundlerConfig: SSRManifest,
_callServer: CallServerCallback,
_chunks: Map<number, SomeChunk<any>>,
...
_partialRow: string,
_fromJSON: (key: string, value: JSONValue) => any,
_stringDecoder: StringDecoder,
};

export type {Response};

function readChunk<T>(chunk: SomeChunk<T>): T {
// If we have resolved content, we try to initialize it first which
// might put us back into one of the other states.
Expand Down Expand Up @@ -512,7 +516,7 @@ function createServerReferenceProxy<A: Iterable<any>, T>(
return proxy;
}

export function parseModelString(
function parseModelString(
response: Response,
parentObject: Object,
key: string,
Expand Down Expand Up @@ -632,7 +636,7 @@ export function parseModelString(
return value;
}

export function parseModelTuple(
function parseModelTuple(
response: Response,
value: {+[key: string]: JSONValue} | $ReadOnlyArray<JSONValue>,
): any {
Expand All @@ -656,17 +660,25 @@ function missingCall() {
export function createResponse(
bundlerConfig: SSRManifest,
callServer: void | CallServerCallback,
): ResponseBase {
): Response {
const chunks: Map<number, SomeChunk<any>> = new Map();
const response = {
const response: Response = {
_bundlerConfig: bundlerConfig,
_callServer: callServer !== undefined ? callServer : missingCall,
_chunks: chunks,
_partialRow: '',
_stringDecoder: (null: any),
_fromJSON: (null: any),
};
if (supportsBinaryStreams) {
response._stringDecoder = createStringDecoder();
}
// Don't inline this call because it causes closure to outline the call above.
response._fromJSON = createFromJSONCallback(response);
return response;
}

export function resolveModel(
function resolveModel(
response: Response,
id: number,
model: UninitializedModel,
Expand All @@ -680,7 +692,7 @@ export function resolveModel(
}
}

export function resolveModule(
function resolveModule(
response: Response,
id: number,
model: UninitializedModel,
Expand Down Expand Up @@ -729,7 +741,7 @@ export function resolveModule(
}

type ErrorWithDigest = Error & {digest?: string};
export function resolveErrorProd(
function resolveErrorProd(
response: Response,
id: number,
digest: string,
Expand Down Expand Up @@ -758,7 +770,7 @@ export function resolveErrorProd(
}
}

export function resolveErrorDev(
function resolveErrorDev(
response: Response,
id: number,
digest: string,
Expand Down Expand Up @@ -789,7 +801,7 @@ export function resolveErrorDev(
}
}

export function resolveHint(
function resolveHint(
response: Response,
code: string,
model: UninitializedModel,
Expand All @@ -798,6 +810,105 @@ export function resolveHint(
dispatchHint(code, hintModel);
}

function processFullRow(response: Response, row: string): void {
if (row === '') {
return;
}
const colon = row.indexOf(':', 0);
const id = parseInt(row.slice(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) {
// }
switch (tag) {
case 'I': {
resolveModule(response, id, row.slice(colon + 2));
return;
}
case 'H': {
const code = row[colon + 2];
resolveHint(response, code, row.slice(colon + 3));
return;
}
case 'E': {
const errorInfo = JSON.parse(row.slice(colon + 2));
if (__DEV__) {
resolveErrorDev(
response,
id,
errorInfo.digest,
errorInfo.message,
errorInfo.stack,
);
} else {
resolveErrorProd(response, id, errorInfo.digest);
}
return;
}
default: {
// We assume anything else is JSON.
resolveModel(response, id, row.slice(colon + 1));
return;
}
}
}

export function processStringChunk(
response: Response,
chunk: string,
offset: number,
): void {
let linebreak = chunk.indexOf('\n', offset);
while (linebreak > -1) {
const fullrow = response._partialRow + chunk.slice(offset, linebreak);
processFullRow(response, fullrow);
response._partialRow = '';
offset = linebreak + 1;
linebreak = chunk.indexOf('\n', offset);
}
response._partialRow += chunk.slice(offset);
}

export function processBinaryChunk(
response: Response,
chunk: Uint8Array,
): void {
if (!supportsBinaryStreams) {
throw new Error("This environment don't support binary chunks.");
}
const stringDecoder = response._stringDecoder;
let linebreak = chunk.indexOf(10); // newline
while (linebreak > -1) {
const fullrow =
response._partialRow +
readFinalStringChunk(stringDecoder, chunk.subarray(0, linebreak));
processFullRow(response, fullrow);
response._partialRow = '';
chunk = chunk.subarray(linebreak + 1);
linebreak = chunk.indexOf(10); // newline
}
response._partialRow += readPartialStringChunk(stringDecoder, chunk);
}

function parseModel<T>(response: Response, json: UninitializedModel): T {
return JSON.parse(json, response._fromJSON);
}

function createFromJSONCallback(response: Response) {
// $FlowFixMe[missing-this-annot]
return function (key: string, value: JSONValue) {
if (typeof value === 'string') {
// We can't use .bind here because we need the "this" value.
return parseModelString(response, this, key, value);
}
if (typeof value === 'object' && value !== null) {
return parseModelTuple(response, value);
}
return value;
};
}

export function close(response: Response): void {
// In case there are any remaining unresolved chunks, they won't
// be resolved now. So we need to issue an error to those.
Expand Down
33 changes: 0 additions & 33 deletions packages/react-client/src/ReactFlightClientConfigNoStream.js

This file was deleted.

23 changes: 0 additions & 23 deletions packages/react-client/src/ReactFlightClientConfigStream.js

This file was deleted.

Loading

0 comments on commit 5309f10

Please sign in to comment.