Skip to content

Commit 7843b14

Browse files
authored
[Fizz/Flight] Pass in Destination lazily to startFlowing instead of in createRequest (#22449)
* Pass in Destination lazily in startFlowing instead of createRequest * Delay fatal errors until we have a destination to forward them to * Flow can now be inferred by whether there's a destination set We can drop the destination when we're not flowing since there's nothing to write to. Fatal errors now close once flowing starts back up again. * Defer fatal errors in Flight too
1 parent d9fb383 commit 7843b14

14 files changed

+110
-88
lines changed

packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ describe('ReactDOMFizzServer', () => {
154154
it('should error the stream when an error is thrown at the root', async () => {
155155
const reportedErrors = [];
156156
const {writable, output, completed} = getTestWritable();
157-
ReactDOMFizzServer.pipeToNodeWritable(
157+
const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
158158
<div>
159159
<Throw />
160160
</div>,
@@ -166,7 +166,8 @@ describe('ReactDOMFizzServer', () => {
166166
},
167167
);
168168

169-
// The stream is errored even if we haven't started writing.
169+
// The stream is errored once we start writing.
170+
startWriting();
170171

171172
await completed;
172173

packages/react-dom/src/server/ReactDOMFizzServerBrowser.js

+10-12
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@ function renderToReadableStream(
3737
children: ReactNodeList,
3838
options?: Options,
3939
): ReadableStream {
40-
let request;
40+
const request = createRequest(
41+
children,
42+
createResponseState(options ? options.identifierPrefix : undefined),
43+
createRootFormatContext(options ? options.namespaceURI : undefined),
44+
options ? options.progressiveChunkSize : undefined,
45+
options ? options.onError : undefined,
46+
options ? options.onCompleteAll : undefined,
47+
options ? options.onCompleteShell : undefined,
48+
);
4149
if (options && options.signal) {
4250
const signal = options.signal;
4351
const listener = () => {
@@ -48,16 +56,6 @@ function renderToReadableStream(
4856
}
4957
const stream = new ReadableStream({
5058
start(controller) {
51-
request = createRequest(
52-
children,
53-
controller,
54-
createResponseState(options ? options.identifierPrefix : undefined),
55-
createRootFormatContext(options ? options.namespaceURI : undefined),
56-
options ? options.progressiveChunkSize : undefined,
57-
options ? options.onError : undefined,
58-
options ? options.onCompleteAll : undefined,
59-
options ? options.onCompleteShell : undefined,
60-
);
6159
startWork(request);
6260
},
6361
pull(controller) {
@@ -66,7 +64,7 @@ function renderToReadableStream(
6664
// is actually used by something so we can give it the best result possible
6765
// at that point.
6866
if (stream.locked) {
69-
startFlowing(request);
67+
startFlowing(request, controller);
7068
}
7169
},
7270
cancel(reason) {},

packages/react-dom/src/server/ReactDOMFizzServerNode.js

+4-9
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
} from './ReactDOMServerFormatConfig';
2626

2727
function createDrainHandler(destination, request) {
28-
return () => startFlowing(request);
28+
return () => startFlowing(request, destination);
2929
}
3030

3131
type Options = {|
@@ -44,14 +44,9 @@ type Controls = {|
4444
startWriting(): void,
4545
|};
4646

47-
function createRequestImpl(
48-
children: ReactNodeList,
49-
destination: Writable,
50-
options: void | Options,
51-
) {
47+
function createRequestImpl(children: ReactNodeList, options: void | Options) {
5248
return createRequest(
5349
children,
54-
destination,
5550
createResponseState(options ? options.identifierPrefix : undefined),
5651
createRootFormatContext(options ? options.namespaceURI : undefined),
5752
options ? options.progressiveChunkSize : undefined,
@@ -66,7 +61,7 @@ function pipeToNodeWritable(
6661
destination: Writable,
6762
options?: Options,
6863
): Controls {
69-
const request = createRequestImpl(children, destination, options);
64+
const request = createRequestImpl(children, options);
7065
let hasStartedFlowing = false;
7166
startWork(request);
7267
return {
@@ -75,7 +70,7 @@ function pipeToNodeWritable(
7570
return;
7671
}
7772
hasStartedFlowing = true;
78-
startFlowing(request);
73+
startFlowing(request, destination);
7974
destination.on('drain', createDrainHandler(destination, request));
8075
},
8176
abort() {

packages/react-dom/src/server/ReactDOMLegacyServerBrowser.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ function renderToStringImpl(
5959
}
6060
const request = createRequest(
6161
children,
62-
destination,
6362
createResponseState(
6463
generateStaticMarkup,
6564
options ? options.identifierPrefix : undefined,
@@ -74,7 +73,7 @@ function renderToStringImpl(
7473
// If anything suspended and is still pending, we'll abort it before writing.
7574
// That way we write only client-rendered boundaries from the start.
7675
abort(request);
77-
startFlowing(request);
76+
startFlowing(request, destination);
7877
if (didFatal) {
7978
throw fatalError;
8079
}

packages/react-dom/src/server/ReactDOMLegacyServerNode.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class ReactMarkupReadableStream extends Readable {
5454

5555
_read(size) {
5656
if (this.startedFlowing) {
57-
startFlowing(this.request);
57+
startFlowing(this.request, this);
5858
}
5959
}
6060
}
@@ -72,12 +72,11 @@ function renderToNodeStreamImpl(
7272
// We wait until everything has loaded before starting to write.
7373
// That way we only end up with fully resolved HTML even if we suspend.
7474
destination.startedFlowing = true;
75-
startFlowing(request);
75+
startFlowing(request, destination);
7676
}
7777
const destination = new ReactMarkupReadableStream();
7878
const request = createRequest(
7979
children,
80-
destination,
8180
createResponseState(false, options ? options.identifierPrefix : undefined),
8281
createRootFormatContext(),
8382
Infinity,

packages/react-noop-renderer/src/ReactNoopFlightServer.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,11 @@ function render(model: ReactModel, options?: Options): Destination {
6363
const bundlerConfig = undefined;
6464
const request = ReactNoopFlightServer.createRequest(
6565
model,
66-
destination,
6766
bundlerConfig,
6867
options ? options.onError : undefined,
6968
);
7069
ReactNoopFlightServer.startWork(request);
71-
ReactNoopFlightServer.startFlowing(request);
70+
ReactNoopFlightServer.startFlowing(request, destination);
7271
return destination;
7372
}
7473

packages/react-noop-renderer/src/ReactNoopServer.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,6 @@ function render(children: React$Element<any>, options?: Options): Destination {
259259
};
260260
const request = ReactNoopServer.createRequest(
261261
children,
262-
destination,
263262
null,
264263
null,
265264
options ? options.progressiveChunkSize : undefined,
@@ -268,7 +267,7 @@ function render(children: React$Element<any>, options?: Options): Destination {
268267
options ? options.onCompleteShell : undefined,
269268
);
270269
ReactNoopServer.startWork(request);
271-
ReactNoopServer.startFlowing(request);
270+
ReactNoopServer.startFlowing(request, destination);
272271
return destination;
273272
}
274273

packages/react-server-dom-relay/src/ReactDOMServerFB.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ function renderToStream(children: ReactNodeList, options: Options): Stream {
4646
};
4747
const request = createRequest(
4848
children,
49-
destination,
5049
createResponseState(options ? options.identifierPrefix : undefined),
5150
createRootFormatContext(undefined),
5251
options ? options.progressiveChunkSize : undefined,
@@ -71,7 +70,7 @@ function abortStream(stream: Stream): void {
7170
function renderNextChunk(stream: Stream): string {
7271
const {request, destination} = stream;
7372
performWork(request);
74-
startFlowing(request);
73+
startFlowing(request, destination);
7574
if (destination.fatal) {
7675
throw destination.error;
7776
}

packages/react-server-dom-relay/src/ReactFlightDOMRelayServer.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,11 @@ function render(
3131
): void {
3232
const request = createRequest(
3333
model,
34-
destination,
3534
config,
3635
options ? options.onError : undefined,
3736
);
3837
startWork(request);
39-
startFlowing(request);
38+
startFlowing(request, destination);
4039
}
4140

4241
export {render};

packages/react-server-dom-webpack/src/ReactFlightDOMServerBrowser.js

+6-8
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,13 @@ function renderToReadableStream(
2525
webpackMap: BundlerConfig,
2626
options?: Options,
2727
): ReadableStream {
28-
let request;
28+
const request = createRequest(
29+
model,
30+
webpackMap,
31+
options ? options.onError : undefined,
32+
);
2933
const stream = new ReadableStream({
3034
start(controller) {
31-
request = createRequest(
32-
model,
33-
controller,
34-
webpackMap,
35-
options ? options.onError : undefined,
36-
);
3735
startWork(request);
3836
},
3937
pull(controller) {
@@ -42,7 +40,7 @@ function renderToReadableStream(
4240
// is actually used by something so we can give it the best result possible
4341
// at that point.
4442
if (stream.locked) {
45-
startFlowing(request);
43+
startFlowing(request, controller);
4644
}
4745
},
4846
cancel(reason) {},

packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
} from 'react-server/src/ReactFlightServer';
1919

2020
function createDrainHandler(destination, request) {
21-
return () => startFlowing(request);
21+
return () => startFlowing(request, destination);
2222
}
2323

2424
type Options = {
@@ -33,12 +33,11 @@ function pipeToNodeWritable(
3333
): void {
3434
const request = createRequest(
3535
model,
36-
destination,
3736
webpackMap,
3837
options ? options.onError : undefined,
3938
);
4039
startWork(request);
41-
startFlowing(request);
40+
startFlowing(request, destination);
4241
destination.on('drain', createDrainHandler(destination, request));
4342
}
4443

packages/react-server-native-relay/src/ReactFlightNativeRelayServer.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ function render(
2424
destination: Destination,
2525
config: BundlerConfig,
2626
): void {
27-
const request = createRequest(model, destination, config);
27+
const request = createRequest(model, config);
2828
startWork(request);
29-
startFlowing(request);
29+
startFlowing(request, destination);
3030
}
3131

3232
export {render};

0 commit comments

Comments
 (0)