[Flight] Add Client Infrastructure (#17234)
* Change demo to server * Expose client in package.json * Reorganize tests We don't want unit tests but instead test how both server and clients work together. So this merges server/client test files. * Fill in the client implementation a bit * Use new client in fixture * Add Promise/Uint8Array to lint rule I'll probably end up deleting these deps later but they're here for now.
Sebastian Markbåge committed
Nov 1, 2019 at 16:05 UTC
fadc97167f8d2387dfc2c7b2493ba9ffbbb35fcf
17 files changed
+239
-377
fixtures/flight-browser/index.html
+22
-19
@@ -18,9 +18,12 @@
18
</div>
19
<script src="../../build/dist/react.development.js"></script>
20
<script src="../../build/dist/react-dom.development.js"></script>
21
+ <script src="../../build/dist/react-dom-unstable-flight-server.browser.development.js"></script>
22
<script src="../../build/dist/react-dom-unstable-flight-client.development.js"></script>
23
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
24
<script type="text/babel">
25
+ let Suspense = React.Suspense;
26
+
27
function Text({children}) {
28
return <span>{children}</span>;
29
}
@@ -40,7 +43,7 @@
43
}
44
};
45
43
- let stream = ReactFlightDOMClient.renderToReadableStream(model);
46
+ let stream = ReactFlightDOMServer.renderToReadableStream(model);
47
let response = new Response(stream, {
48
headers: {'Content-Type': 'text/html'},
49
});
@@ -49,35 +52,35 @@
52
async function display(responseToDisplay) {
53
let blob = await responseToDisplay.blob();
54
let url = URL.createObjectURL(blob);
52
- let response = await fetch(url);
53
- let body = await response.body;
55
55
- let reader = body.getReader();
56
- let charsReceived = 0;
57
- let decoder = new TextDecoder();
56
+ let data = ReactFlightDOMClient.readFromFetch(
57
+ fetch(url)
58
+ );
59
+ // The client also supports XHR streaming.
60
+ // var xhr = new XMLHttpRequest();
61
+ // xhr.open('GET', url);
62
+ // let data = ReactFlightDOMClient.readFromXHR(xhr);
63
+ // xhr.send();
64
59
- let json = '';
60
- reader.read().then(function processChunk({ done, value }) {
61
- if (done) {
62
- renderResult(json);
63
- return;
64
- }
65
- json += decoder.decode(value);
66
- return reader.read().then(processChunk);
67
- });
65
+ renderResult(data);
66
}
67
70
- function Shell({ model }) {
68
+ function Shell({ data }) {
69
+ let model = data.model;
70
return <div>
71
<h1>{model.title}</h1>
72
<div dangerouslySetInnerHTML={model.content} />
73
</div>;
74
}
75
77
- function renderResult(json) {
78
- let model = JSON.parse(json);
76
+ function renderResult(data) {
77
let container = document.getElementById('container');
80
- ReactDOM.render(<Shell model={model} />, container);
78
+ ReactDOM.render(
79
+ <Suspense fallback="Loading...">
80
+ <Shell data={data} />
81
+ </Suspense>,
82
+ container
83
+ );
84
}
85
</script>
86
</body>
packages/react-dom/package.json
+1
@@ -39,6 +39,7 @@
39
"unstable-fizz.js",
40
"unstable-fizz.browser.js",
41
"unstable-fizz.node.js",
42
+ "unstable-flight-client.js",
43
"unstable-flight-server.js",
44
"unstable-flight-server.browser.js",
45
"unstable-flight-server.node.js",
packages/react-dom/src/__tests__/ReactFlightDOMBrowser-test.js
renamed
packages/react-dom/src/__tests__/ReactFlightDOMNode-test.js
renamed
packages/react-dom/src/client/flight/ReactFlightDOMClient.js
+68
-16
@@ -7,28 +7,80 @@
7
* @flow
8
*/
9
10
-import type {ReactModel} from 'react-flight/src/ReactFlightClient';
10
+import type {ReactModelRoot} from 'react-flight/src/ReactFlightClient';
11
12
import {
13
- createRequest,
14
- startWork,
15
- startFlowing,
16
-} from 'react-flight/inline.dom-browser';
13
+ createResponse,
14
+ getModelRoot,
15
+ reportGlobalError,
16
+ processStringChunk,
17
+ processBinaryChunk,
18
+ complete,
19
+} from 'react-flight/inline.dom';
20
18
-function renderToReadableStream(model: ReactModel): ReadableStream {
19
- let request;
20
- return new ReadableStream({
21
- start(controller) {
22
- request = createRequest(model, controller);
23
- startWork(request);
21
+function startReadingFromStream(response, stream: ReadableStream): void {
22
+ let reader = stream.getReader();
23
+ function progress({done, value}) {
24
+ if (done) {
25
+ complete(response);
26
+ return;
27
+ }
28
+ let buffer: Uint8Array = (value: any);
29
+ processBinaryChunk(response, buffer, 0);
30
+ return reader.read().then(progress, error);
31
+ }
32
+ function error(e) {
33
+ reportGlobalError(response, e);
34
+ }
35
+ reader.read().then(progress, error);
36
+}
37
+
38
+function readFromReadableStream<T>(stream: ReadableStream): ReactModelRoot<T> {
39
+ let response = createResponse(stream);
40
+ startReadingFromStream(response, stream);
41
+ return getModelRoot(response);
42
+}
43
+
44
+function readFromFetch<T>(
45
+ promiseForResponse: Promise<Response>,
46
+): ReactModelRoot<T> {
47
+ let response = createResponse(promiseForResponse);
48
+ promiseForResponse.then(
49
+ function(r) {
50
+ startReadingFromStream(response, (r.body: any));
51
},
25
- pull(controller) {
26
- startFlowing(request, controller.desiredSize);
52
+ function(e) {
53
+ reportGlobalError(response, e);
54
},
28
- cancel(reason) {},
29
- });
55
+ );
56
+ return getModelRoot(response);
57
+}
58
+
59
+function readFromXHR<T>(request: XMLHttpRequest): ReactModelRoot<T> {
60
+ let response = createResponse(request);
61
+ let processedLength = 0;
62
+ function progress(e: ProgressEvent): void {
63
+ let chunk = request.responseText;
64
+ processStringChunk(response, chunk, processedLength);
65
+ processedLength = chunk.length;
66
+ }
67
+ function load(e: ProgressEvent): void {
68
+ progress(e);
69
+ complete(response);
70
+ }
71
+ function error(e: ProgressEvent): void {
72
+ reportGlobalError(response, new TypeError('Network error'));
73
+ }
74
+ request.addEventListener('progress', progress);
75
+ request.addEventListener('load', load);
76
+ request.addEventListener('error', error);
77
+ request.addEventListener('abort', error);
78
+ request.addEventListener('timeout', error);
79
+ return getModelRoot(response);
80
}
81
82
export default {
33
- renderToReadableStream,
83
+ readFromXHR,
84
+ readFromFetch,
85
+ readFromReadableStream,
86
};
packages/react-dom/src/client/flight/ReactFlightDOMHostConfig.js
+16
-32
@@ -7,44 +7,28 @@
7
* @flow
8
*/
9
10
-export type Destination = ReadableStreamController;
10
+export type Source = Promise<Response> | ReadableStream | XMLHttpRequest;
11
12
-export function scheduleWork(callback: () => void) {
13
- callback();
14
-}
15
-
16
-export function flushBuffered(destination: Destination) {
17
- // WHATWG Streams do not yet have a way to flush the underlying
18
- // transform streams. https://github.com/whatwg/streams/issues/960
19
-}
20
-
21
-export function beginWriting(destination: Destination) {}
12
+export type StringDecoder = TextDecoder;
13
23
-export function writeChunk(destination: Destination, buffer: Uint8Array) {
24
- destination.enqueue(buffer);
25
-}
26
-
27
-export function completeWriting(destination: Destination) {}
14
+export const supportsBinaryStreams = true;
15
29
-export function close(destination: Destination) {
30
- destination.close();
16
+export function createStringDecoder(): StringDecoder {
17
+ return new TextDecoder();
18
}
19
33
-const textEncoder = new TextEncoder();
34
-
35
-export function convertStringToBuffer(content: string): Uint8Array {
36
- return textEncoder.encode(content);
37
-}
20
+const decoderOptions = {stream: true};
21
39
-export function formatChunkAsString(type: string, props: Object): string {
40
- let str = '<' + type + '>';
41
- if (typeof props.children === 'string') {
42
- str += props.children;
43
- }
44
- str += '</' + type + '>';
45
- return str;
22
+export function readPartialStringChunk(
23
+ decoder: StringDecoder,
24
+ buffer: Uint8Array,
25
+): string {
26
+ return decoder.decode(buffer, decoderOptions);
27
}
28
48
-export function formatChunk(type: string, props: Object): Uint8Array {
49
- return convertStringToBuffer(formatChunkAsString(type, props));
29
+export function readFinalStringChunk(
30
+ decoder: StringDecoder,
31
+ buffer: Uint8Array,
32
+): string {
33
+ return decoder.decode(buffer);
34
}
packages/react-dom/src/server/flight/__tests__/ReactFlightDOMBrowser-test.js
deleted
-61
@@ -1,61 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @emails react-core
8
- */
9
-
10
-'use strict';
11
-
12
-// Polyfills for test environment
13
-global.ReadableStream = require('@mattiasbuelens/web-streams-polyfill/ponyfill/es6').ReadableStream;
14
-global.TextEncoder = require('util').TextEncoder;
15
-
16
-let React;
17
-let ReactFlightDOMServer;
18
-
19
-describe('ReactFlightDOM', () => {
20
- beforeEach(() => {
21
- jest.resetModules();
22
- React = require('react');
23
- ReactFlightDOMServer = require('react-dom/unstable-flight-server.browser');
24
- });
25
-
26
- async function readResult(stream) {
27
- let reader = stream.getReader();
28
- let result = '';
29
- while (true) {
30
- let {done, value} = await reader.read();
31
- if (done) {
32
- return result;
33
- }
34
- result += Buffer.from(value).toString('utf8');
35
- }
36
- }
37
-
38
- it('should resolve HTML', async () => {
39
- function Text({children}) {
40
- return <span>{children}</span>;
41
- }
42
- function HTML() {
43
- return (
44
- <div>
45
- <Text>hello</Text>
46
- <Text>world</Text>
47
- </div>
48
- );
49
- }
50
-
51
- let model = {
52
- html: <HTML />,
53
- };
54
- let stream = ReactFlightDOMServer.renderToReadableStream(model);
55
- jest.runAllTimers();
56
- let result = JSON.parse(await readResult(stream));
57
- expect(result).toEqual({
58
- html: '<div><span>hello</span><span>world</span></div>',
59
- });
60
- });
61
-});
packages/react-dom/src/server/flight/__tests__/ReactFlightDOMNode-test.js
deleted
-57
@@ -1,57 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @emails react-core
8
- * @jest-environment node
9
- */
10
-
11
-'use strict';
12
-
13
-let Stream;
14
-let React;
15
-let ReactFlightDOMServer;
16
-
17
-describe('ReactFlightDOM', () => {
18
- beforeEach(() => {
19
- jest.resetModules();
20
- React = require('react');
21
- ReactFlightDOMServer = require('react-dom/unstable-flight-server');
22
- Stream = require('stream');
23
- });
24
-
25
- function getTestWritable() {
26
- let writable = new Stream.PassThrough();
27
- writable.setEncoding('utf8');
28
- writable.result = '';
29
- writable.on('data', chunk => (writable.result += chunk));
30
- return writable;
31
- }
32
-
33
- it('should resolve HTML', () => {
34
- function Text({children}) {
35
- return <span>{children}</span>;
36
- }
37
- function HTML() {
38
- return (
39
- <div>
40
- <Text>hello</Text>
41
- <Text>world</Text>
42
- </div>
43
- );
44
- }
45
-
46
- let writable = getTestWritable();
47
- let model = {
48
- html: <HTML />,
49
- };
50
- ReactFlightDOMServer.pipeToNodeWritable(model, writable);
51
- jest.runAllTimers();
52
- let result = JSON.parse(writable.result);
53
- expect(result).toEqual({
54
- html: '<div><span>hello</span><span>world</span></div>',
55
- });
56
- });
57
-});
packages/react-flight/src/ReactFlightClient.js
+89
-112
@@ -7,138 +7,115 @@
7
* @flow
8
*/
9
10
-import type {Destination} from './ReactFlightClientHostConfig';
10
+import type {Source, StringDecoder} from './ReactFlightClientHostConfig';
11
12
import {
13
- scheduleWork,
14
- beginWriting,
15
- writeChunk,
16
- completeWriting,
17
- flushBuffered,
18
- close,
19
- convertStringToBuffer,
20
- formatChunkAsString,
13
+ supportsBinaryStreams,
14
+ createStringDecoder,
15
+ readPartialStringChunk,
16
+ readFinalStringChunk,
17
} from './ReactFlightClientHostConfig';
22
-import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
18
24
-export type ReactModel =
25
- | React$Element<any>
26
- | string
27
- | boolean
28
- | number
29
- | null
30
- | Iterable<ReactModel>
31
- | ReactModelObject;
19
+export type ReactModelRoot<T> = {|
20
+ model: T,
21
+|};
22
33
-type ReactJSONValue =
34
- | string
35
- | boolean
36
- | number
37
- | null
38
- | Array<ReactModel>
39
- | ReactModelObject;
40
-
41
-type ReactModelObject = {
42
- +[key: string]: ReactModel,
43
-};
44
-
45
-type OpaqueRequest = {
46
- destination: Destination,
47
- model: ReactModel,
48
- completedChunks: Array<Uint8Array>,
49
- flowing: boolean,
23
+type OpaqueResponse = {
24
+ source: Source,
25
+ modelRoot: ReactModelRoot<any>,
26
+ partialRow: string,
27
+ stringDecoder: StringDecoder,
28
+ rootPing: () => void,
29
};
30
52
-export function createRequest(
53
- model: ReactModel,
54
- destination: Destination,
55
-): OpaqueRequest {
56
- return {destination, model, completedChunks: [], flowing: false};
57
-}
31
+export function createResponse(source: Source): OpaqueResponse {
32
+ let modelRoot = {};
33
+ Object.defineProperty(
34
+ modelRoot,
35
+ 'model',
36
+ ({
37
+ configurable: true,
38
+ enumerable: true,
39
+ get() {
40
+ throw rootPromise;
41
+ },
42
+ }: any),
43
+ );
44
59
-function resolveChildToHostFormat(child: ReactJSONValue): string {
60
- if (typeof child === 'string') {
61
- return child;
62
- } else if (typeof child === 'number') {
63
- return '' + child;
64
- } else if (typeof child === 'boolean' || child === null) {
65
- // Booleans are like null when they're React children.
66
- return '';
67
- } else if (Array.isArray(child)) {
68
- return (child: Array<ReactModel>)
69
- .map(c => resolveChildToHostFormat(resolveModelToJSON('', c)))
70
- .join('');
71
- } else {
72
- throw new Error('Object models are not valid as children of host nodes.');
45
+ let rootPing;
46
+ let rootPromise = new Promise(resolve => {
47
+ rootPing = resolve;
48
+ });
49
+
50
+ let response: OpaqueResponse = ({
51
+ source,
52
+ modelRoot,
53
+ partialRow: '',
54
+ rootPing,
55
+ }: any);
56
+ if (supportsBinaryStreams) {
57
+ response.stringDecoder = createStringDecoder();
58
}
59
+ return response;
60
}
61
76
-function resolveElementToHostFormat(type: string, props: Object): string {
77
- let child = resolveModelToJSON('', props.children);
78
- let childString = resolveChildToHostFormat(child);
79
- return formatChunkAsString(
80
- type,
81
- Object.assign({}, props, {children: childString}),
62
+// Report that any missing chunks in the model is now going to throw this
63
+// error upon read. Also notify any pending promises.
64
+export function reportGlobalError(
65
+ response: OpaqueResponse,
66
+ error: Error,
67
+): void {
68
+ Object.defineProperty(
69
+ response.modelRoot,
70
+ 'model',
71
+ ({
72
+ configurable: true,
73
+ enumerable: true,
74
+ get() {
75
+ throw error;
76
+ },
77
+ }: any),
78
);
79
+ response.rootPing();
80
}
81
85
-function resolveModelToJSON(key: string, value: ReactModel): ReactJSONValue {
86
- while (value && value.$$typeof === REACT_ELEMENT_TYPE) {
87
- let element: React$Element<any> = (value: any);
88
- let type = element.type;
89
- let props = element.props;
90
- if (typeof type === 'function') {
91
- // This is a nested view model.
92
- value = type(props);
93
- continue;
94
- } else if (typeof type === 'string') {
95
- // This is a host element. E.g. HTML.
96
- return resolveElementToHostFormat(type, props);
97
- } else {
98
- throw new Error('Unsupported type.');
99
- }
100
- }
101
- return value;
82
+export function processStringChunk(
83
+ response: OpaqueResponse,
84
+ chunk: string,
85
+ offset: number,
86
+): void {
87
+ response.partialRow += chunk.substr(offset);
88
}
89
104
-function performWork(request: OpaqueRequest): void {
105
- let rootModel = request.model;
106
- request.model = null;
107
- let json = JSON.stringify(rootModel, resolveModelToJSON);
108
- request.completedChunks.push(convertStringToBuffer(json));
109
- if (request.flowing) {
110
- flushCompletedChunks(request);
90
+export function processBinaryChunk(
91
+ response: OpaqueResponse,
92
+ chunk: Uint8Array,
93
+ offset: number,
94
+): void {
95
+ if (!supportsBinaryStreams) {
96
+ throw new Error("This environment don't support binary chunks.");
97
}
112
-
113
- flushBuffered(request.destination);
98
+ response.partialRow += readPartialStringChunk(response.stringDecoder, chunk);
99
}
100
116
-function flushCompletedChunks(request: OpaqueRequest) {
117
- let destination = request.destination;
118
- let chunks = request.completedChunks;
119
- request.completedChunks = [];
120
-
121
- beginWriting(destination);
122
- try {
123
- for (let i = 0; i < chunks.length; i++) {
124
- let chunk = chunks[i];
125
- writeChunk(destination, chunk);
126
- }
127
- } finally {
128
- completeWriting(destination);
101
+let emptyBuffer = new Uint8Array(0);
102
+export function complete(response: OpaqueResponse): void {
103
+ if (supportsBinaryStreams) {
104
+ // This should never be needed since we're expected to have complete
105
+ // code units at the end of JSON.
106
+ response.partialRow += readFinalStringChunk(
107
+ response.stringDecoder,
108
+ emptyBuffer,
109
+ );
110
}
130
- close(destination);
111
+ let modelRoot = response.modelRoot;
112
+ let model = JSON.parse(response.partialRow);
113
+ Object.defineProperty(modelRoot, 'model', {
114
+ value: model,
115
+ });
116
+ response.rootPing();
117
}
118
133
-export function startWork(request: OpaqueRequest): void {
134
- request.flowing = true;
135
- scheduleWork(() => performWork(request));
136
-}
137
-
138
-export function startFlowing(
139
- request: OpaqueRequest,
140
- desiredBytes: number,
141
-): void {
142
- request.flowing = false;
143
- flushCompletedChunks(request);
119
+export function getModelRoot<T>(response: OpaqueResponse): ReactModelRoot<T> {
120
+ return response.modelRoot;
121
}
packages/react-flight/src/__tests__/ReactFlight-test.js
renamed
+7
-3
@@ -11,13 +11,15 @@
11
'use strict';
12
13
let React;
14
+let ReactNoopFlightServer;
15
let ReactNoopFlightClient;
16
16
-describe('ReactFlightClient', () => {
17
+describe('ReactFlight', () => {
18
beforeEach(() => {
19
jest.resetModules();
20
21
React = require('react');
22
+ ReactNoopFlightServer = require('react-noop-renderer/flight-server');
23
ReactNoopFlightClient = require('react-noop-renderer/flight-client');
24
});
25
@@ -30,9 +32,11 @@ describe('ReactFlightClient', () => {
32
bar: [<Bar text="a" />, <Bar text="b" />],
33
};
34
}
33
- let result = ReactNoopFlightClient.render({
35
+ let transport = ReactNoopFlightServer.render({
36
foo: <Foo />,
37
});
36
- expect(result).toEqual([{foo: {bar: ['A', 'B']}}]);
38
+ let root = ReactNoopFlightClient.read(transport);
39
+ let model = root.model;
40
+ expect(model).toEqual({foo: {bar: ['A', 'B']}});
41
});
42
});
packages/react-flight/src/forks/ReactFlightClientHostConfig.custom.js
+6
-10
@@ -24,14 +24,10 @@
24
// really an argument to a top-level wrapping function.
25
26
declare var $$$hostConfig: any;
27
-export opaque type Destination = mixed; // eslint-disable-line no-undef
27
+export opaque type Source = mixed; // eslint-disable-line no-undef
28
+export opaque type StringDecoder = mixed; // eslint-disable-line no-undef
29
29
-export const formatChunkAsString = $$$hostConfig.formatChunkAsString;
30
-export const formatChunk = $$$hostConfig.formatChunk;
31
-export const scheduleWork = $$$hostConfig.scheduleWork;
32
-export const beginWriting = $$$hostConfig.beginWriting;
33
-export const writeChunk = $$$hostConfig.writeChunk;
34
-export const completeWriting = $$$hostConfig.completeWriting;
35
-export const flushBuffered = $$$hostConfig.flushBuffered;
36
-export const close = $$$hostConfig.close;
37
-export const convertStringToBuffer = $$$hostConfig.convertStringToBuffer;
30
+export const supportsBinaryStreams = $$$hostConfig.supportsBinaryStreams;
31
+export const createStringDecoder = $$$hostConfig.createStringDecoder;
32
+export const readPartialStringChunk = $$$hostConfig.readPartialStringChunk;
33
+export const readFinalStringChunk = $$$hostConfig.readFinalStringChunk;
packages/react-noop-renderer/src/ReactNoopFlightClient.js
+17
-28
@@ -14,41 +14,30 @@
14
* environment.
15
*/
16
17
-import type {ReactModel} from 'react-flight/inline-typed';
17
+import type {ReactModelRoot} from 'react-flight/inline-typed';
18
19
import ReactFlightClient from 'react-flight';
20
21
-type Destination = Array<string>;
21
+type Source = Array<string>;
22
23
-const ReactNoopFlightClient = ReactFlightClient({
24
- scheduleWork(callback: () => void) {
25
- callback();
26
- },
27
- beginWriting(destination: Destination): void {},
28
- writeChunk(destination: Destination, buffer: Uint8Array): void {
29
- destination.push(JSON.parse(Buffer.from((buffer: any)).toString('utf8')));
30
- },
31
- completeWriting(destination: Destination): void {},
32
- close(destination: Destination): void {},
33
- flushBuffered(destination: Destination): void {},
34
- convertStringToBuffer(content: string): Uint8Array {
35
- return Buffer.from(content, 'utf8');
36
- },
37
- formatChunkAsString(type: string, props: Object): string {
38
- return JSON.stringify({type, props});
39
- },
40
- formatChunk(type: string, props: Object): Uint8Array {
41
- return Buffer.from(JSON.stringify({type, props}), 'utf8');
42
- },
23
+const {
24
+ createResponse,
25
+ getModelRoot,
26
+ processStringChunk,
27
+ complete,
28
+} = ReactFlightClient({
29
+ supportsBinaryStreams: false,
30
});
31
45
-function render(model: ReactModel): Destination {
46
- let destination: Destination = [];
47
- let request = ReactNoopFlightClient.createRequest(model, destination);
48
- ReactNoopFlightClient.startWork(request);
49
- return destination;
32
+function read<T>(source: Source): ReactModelRoot<T> {
33
+ let response = createResponse(source);
34
+ for (let i = 0; i < source.length; i++) {
35
+ processStringChunk(response, source[i], 0);
36
+ }
37
+ complete(response);
38
+ return getModelRoot(response);
39
}
40
41
export default {
53
- render,
42
+ read,
43
};
packages/react-noop-renderer/src/ReactNoopFlightServer.js
+1
-1
@@ -26,7 +26,7 @@ const ReactNoopFlightServer = ReactFlightStreamer({
26
},
27
beginWriting(destination: Destination): void {},
28
writeChunk(destination: Destination, buffer: Uint8Array): void {
29
- destination.push(JSON.parse(Buffer.from((buffer: any)).toString('utf8')));
29
+ destination.push(Buffer.from((buffer: any)).toString('utf8'));
30
},
31
completeWriting(destination: Destination): void {},
32
close(destination: Destination): void {},
packages/react-server/src/__tests__/ReactFlightServer-test.js
deleted
-38
@@ -1,38 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @emails react-core
8
- * @jest-environment node
9
- */
10
-
11
-'use strict';
12
-
13
-let React;
14
-let ReactNoopFlight;
15
-
16
-describe('ReactFlightServer', () => {
17
- beforeEach(() => {
18
- jest.resetModules();
19
-
20
- React = require('react');
21
- ReactNoopFlight = require('react-noop-renderer/flight-server');
22
- });
23
-
24
- it('can resolve a model', () => {
25
- function Bar({text}) {
26
- return text.toUpperCase();
27
- }
28
- function Foo() {
29
- return {
30
- bar: [<Bar text="a" />, <Bar text="b" />],
31
- };
32
- }
33
- let result = ReactNoopFlight.render({
34
- foo: <Foo />,
35
- });
36
- expect(result).toEqual([{foo: {bar: ['A', 'B']}}]);
37
- });
38
-});
scripts/rollup/validate/eslintrc.cjs.js
+4
@@ -28,6 +28,10 @@ module.exports = {
28
SharedArrayBuffer: true,
29
Int32Array: true,
30
ArrayBuffer: true,
31
+
32
+ // Flight
33
+ Uint8Array: true,
34
+ Promise: true,
35
},
36
parserOptions: {
37
ecmaVersion: 5,
scripts/rollup/validate/eslintrc.fb.js
+4
@@ -29,6 +29,10 @@ module.exports = {
29
SharedArrayBuffer: true,
30
Int32Array: true,
31
ArrayBuffer: true,
32
+
33
+ // Flight
34
+ Uint8Array: true,
35
+ Promise: true,
36
},
37
parserOptions: {
38
ecmaVersion: 5,
scripts/rollup/validate/eslintrc.umd.js
+4
@@ -31,6 +31,10 @@ module.exports = {
31
SharedArrayBuffer: true,
32
Int32Array: true,
33
ArrayBuffer: true,
34
+
35
+ // Flight
36
+ Uint8Array: true,
37
+ Promise: true,
38
},
39
parserOptions: {
40
ecmaVersion: 5,