Skip to content

Commit

Permalink
Expose lower level async hooks to Relay
Browse files Browse the repository at this point in the history
This requires an external helper file that we'll wire up internally.
  • Loading branch information
sebmarkbage committed Mar 10, 2020
1 parent a64c5e1 commit b906235
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 70 deletions.
40 changes: 13 additions & 27 deletions packages/react-flight-dom-relay/src/ReactFlightDOMRelayClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
* @flow
*/

import type {ReactModelRoot} from 'react-client/src/ReactFlightClient';

import type {Chunk} from './ReactFlightDOMRelayClientHostConfig';
import type {Response, JSONValue} from 'react-client/src/ReactFlightClient';

import {
createResponse,
Expand All @@ -20,8 +18,6 @@ import {
close,
} from 'react-client/src/ReactFlightClient';

type EncodedData = Array<Chunk>;

function parseModel(response, targetObj, key, value) {
if (typeof value === 'object' && value !== null) {
if (Array.isArray(value)) {
Expand All @@ -42,27 +38,17 @@ function parseModel(response, targetObj, key, value) {
return parseModelFromJSON(response, targetObj, key, value);
}

function read<T>(data: EncodedData): ReactModelRoot<T> {
let response = createResponse();
for (let i = 0; i < data.length; i++) {
let chunk = data[i];
if (chunk.type === 'json') {
resolveModelChunk(
response,
chunk.id,
parseModel(response, {}, '', chunk.json),
);
} else {
resolveErrorChunk(
response,
chunk.id,
chunk.json.message,
chunk.json.stack,
);
}
}
close(response);
return getModelRoot(response);
export {createResponse, getModelRoot, close};

export function resolveModel(response: Response, id: number, json: JSONValue) {
resolveModelChunk(response, id, parseModel(response, {}, '', json));
}

export {read};
export function resolveError(
response: Response,
id: number,
message: string,
stack: string,
) {
resolveErrorChunk(response, id, message, stack);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,6 @@
* @flow
*/

type JSONValue =
| string
| number
| boolean
| null
| {[key: string]: JSONValue}
| Array<JSONValue>;

export type Chunk =
| {
type: 'json',
id: number,
json: JSONValue,
}
| {
type: 'error',
id: number,
json: {
message: string,
stack: string,
...
},
};

export type StringDecoder = void;

export const supportsBinaryStreams = false;
Expand Down
10 changes: 3 additions & 7 deletions packages/react-flight-dom-relay/src/ReactFlightDOMRelayServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@
*/

import type {ReactModel} from 'react-server/src/ReactFlightServer';
import type {Chunk} from './ReactFlightDOMRelayServerHostConfig';
import type {Destination} from './ReactFlightDOMRelayServerHostConfig';

import {createRequest, startWork} from 'react-server/src/ReactFlightServer';

type EncodedData = Array<Chunk>;

function render(model: ReactModel): EncodedData {
let data: EncodedData = [];
let request = createRequest(model, data);
function render(model: ReactModel, destination: Destination): void {
let request = createRequest(model, destination);
startWork(request);
return data;
}

export {render};
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@

import type {Request, ReactModel} from 'react-server/src/ReactFlightServer';

import type {Destination} from 'ReactFlightDOMRelayServerIntegration';

import {resolveModelToJSON} from 'react-server/src/ReactFlightServer';

export type Destination = Array<Chunk>;
import {emitModel, emitError} from 'ReactFlightDOMRelayServerIntegration';

export type {Destination} from 'ReactFlightDOMRelayServerIntegration';

type JSONValue =
| string
Expand Down Expand Up @@ -95,10 +99,14 @@ export function flushBuffered(destination: Destination) {}
export function beginWriting(destination: Destination) {}

export function writeChunk(destination: Destination, chunk: Chunk): boolean {
destination.push(chunk);
if (chunk.type === 'json') {
emitModel(destination, chunk.id, chunk.json);
} else {
emitError(destination, chunk.id, chunk.json.message, chunk.json.stack);
}
return true;
}

export function completeWriting(destination: Destination) {}

export function close(destination: Destination) {}
export {close} from 'ReactFlightDOMRelayServerIntegration';
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

const ReactFlightDOMRelayServerIntegration = {
emitModel(destination, id, json) {
destination.push({
type: 'json',
id: id,
json: json,
});
},
emitError(destination, id, message, stack) {
destination.push({
type: 'error',
id: id,
json: {message, stack},
});
},
close(destination) {},
};

module.exports = ReactFlightDOMRelayServerIntegration;
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@

'use strict';

// Polyfills for test environment
global.TextDecoder = require('util').TextDecoder;

let React;
let ReactDOMFlightRelayServer;
let ReactDOMFlightRelayClient;
Expand All @@ -32,11 +29,30 @@ describe('ReactFlightDOMRelay', () => {
bar: [<Bar text="a" />, <Bar text="b" />],
};
}
let data = ReactDOMFlightRelayServer.render({
foo: <Foo />,
});
let root = ReactDOMFlightRelayClient.read(data);
let model = root.model;
let data = [];
ReactDOMFlightRelayServer.render(
{
foo: <Foo />,
},
data,
);

let response = ReactDOMFlightRelayClient.createResponse();
for (let i = 0; i < data.length; i++) {
let chunk = data[i];
if (chunk.type === 'json') {
ReactDOMFlightRelayClient.resolveModel(response, chunk.id, chunk.json);
} else {
ReactDOMFlightRelayClient.resolveError(
response,
chunk.id,
chunk.json.message,
chunk.json.stack,
);
}
}
let model = ReactDOMFlightRelayClient.getModelRoot(response).model;
ReactDOMFlightRelayClient.close(response);
expect(model).toEqual({foo: {bar: ['A', 'B']}});
});
});
1 change: 1 addition & 0 deletions scripts/flow/config/flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
../environment.js
../react-devtools.js
../react-native-host-hooks.js
../react-relay-hooks.js

[lints]
untyped-type-import=error
Expand Down
32 changes: 32 additions & 0 deletions scripts/flow/react-relay-hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

type JSONValue =
| string
| number
| boolean
| null
| {[key: string]: JSONValue}
| Array<JSONValue>;

declare module 'ReactFlightDOMRelayServerIntegration' {
declare export opaque type Destination;
declare export function emitModel(
destination: Destination,
id: number,
json: JSONValue,
): void;
declare export function emitError(
destination: Destination,
id: number,
message: string,
stack: string,
): void;
declare export function close(destination: Destination): void;
}
6 changes: 5 additions & 1 deletion scripts/rollup/bundles.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,11 @@ const bundles = [
moduleType: RENDERER,
entry: 'react-flight-dom-relay/server',
global: 'ReactFlightDOMRelayServer',
externals: ['react', 'react-dom/server'],
externals: [
'react',
'react-dom/server',
'ReactFlightDOMRelayServerIntegration',
],
},

/******* React DOM Flight Client Relay *******/
Expand Down

0 comments on commit b906235

Please sign in to comment.