diff --git a/fixtures/flight/server/handler.server.js b/fixtures/flight/server/handler.server.js index cdaef9f13a8be..f695f0366e70a 100644 --- a/fixtures/flight/server/handler.server.js +++ b/fixtures/flight/server/handler.server.js @@ -22,10 +22,9 @@ module.exports = function(req, res) { const moduleMap = JSON.parse(data); const {startWriting} = renderToNodePipe( React.createElement(App), - res, moduleMap ); - startWriting(); + startWriting(res); } ); }); diff --git a/fixtures/ssr/server/render.js b/fixtures/ssr/server/render.js index 4922c5cdf7e44..63a795718cc7b 100644 --- a/fixtures/ssr/server/render.js +++ b/fixtures/ssr/server/render.js @@ -20,12 +20,12 @@ export default function render(url, res) { console.error('Fatal', error); }); let didError = false; - const {startWriting, abort} = renderToNodePipe(, res, { + const {startWriting, abort} = renderToNodePipe(, { onCompleteShell() { // If something errored before we started streaming, we set the error code appropriately. res.statusCode = didError ? 500 : 200; res.setHeader('Content-type', 'text/html'); - startWriting(); + startWriting(res); }, onError(x) { didError = true; diff --git a/fixtures/ssr2/server/render.js b/fixtures/ssr2/server/render.js index 92a4f248f3fa2..aa17e1121b0e0 100644 --- a/fixtures/ssr2/server/render.js +++ b/fixtures/ssr2/server/render.js @@ -41,13 +41,12 @@ module.exports = function render(url, res) { , - res, { onCompleteShell() { // If something errored before we started streaming, we set the error code appropriately. res.statusCode = didError ? 500 : 200; res.setHeader('Content-type', 'text/html'); - startWriting(); + startWriting(res); }, onError(x) { didError = true; diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index b368cedede5a7..bc5d127c35184 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -252,9 +252,8 @@ describe('ReactDOMFizzServer', () => { , - writable, ); - startWriting(); + startWriting(writable); }); expect(getVisibleChildren(container)).toEqual(
@@ -306,14 +305,14 @@ describe('ReactDOMFizzServer', () => { await act(async () => { const {startWriting} = ReactDOMFizzServer.renderToNodePipe( , - writable, + { onError(x) { loggedErrors.push(x); }, }, ); - startWriting(); + startWriting(writable); }); expect(loggedErrors).toEqual([]); @@ -362,9 +361,8 @@ describe('ReactDOMFizzServer', () => { {lazyElement}
, - writable, ); - startWriting(); + startWriting(writable); }); expect(getVisibleChildren(container)).toEqual(
Loading...
); await act(async () => { @@ -398,14 +396,14 @@ describe('ReactDOMFizzServer', () => { await act(async () => { const {startWriting} = ReactDOMFizzServer.renderToNodePipe( , - writable, + { onError(x) { loggedErrors.push(x); }, }, ); - startWriting(); + startWriting(writable); }); expect(loggedErrors).toEqual([]); @@ -447,9 +445,8 @@ describe('ReactDOMFizzServer', () => { , - writable, ); - startWriting(); + startWriting(writable); }); expect(getVisibleChildren(container)).toEqual(
Loading...
); await act(async () => { @@ -475,11 +472,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( - , - writable, - ); - startWriting(); + const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); + startWriting(writable); }); // We're still showing a fallback. @@ -552,14 +546,14 @@ describe('ReactDOMFizzServer', () => { await act(async () => { const {startWriting} = ReactDOMFizzServer.renderToNodePipe( , - writable, + { onError(x) { loggedErrors.push(x); }, }, ); - startWriting(); + startWriting(writable); }); // We're still showing a fallback. @@ -635,9 +629,8 @@ describe('ReactDOMFizzServer', () => { await act(async () => { const {startWriting} = ReactDOMFizzServer.renderToNodePipe( , - writable, ); - startWriting(); + startWriting(writable); }); const root = ReactDOM.createRoot(container, {hydrate: true}); @@ -701,8 +694,8 @@ describe('ReactDOMFizzServer', () => { let controls; await act(async () => { - controls = ReactDOMFizzServer.renderToNodePipe(, writable); - controls.startWriting(); + controls = ReactDOMFizzServer.renderToNodePipe(); + controls.startWriting(writable); }); // We're still showing a fallback. @@ -765,12 +758,11 @@ describe('ReactDOMFizzServer', () => { , - writableA, { identifierPrefix: 'A_', onCompleteShell() { writableA.write('
'); - startWriting(); + startWriting(writableA); writableA.write('
'); }, }, @@ -785,12 +777,11 @@ describe('ReactDOMFizzServer', () => { , - writableB, { identifierPrefix: 'B_', onCompleteShell() { writableB.write('
'); - startWriting(); + startWriting(writableB); writableB.write('
'); }, }, @@ -876,11 +867,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( - , - writable, - ); - startWriting(); + const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); + startWriting(writable); }); expect(getVisibleChildren(container)).toEqual( @@ -967,11 +955,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( - , - writable, - ); - startWriting(); + const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); + startWriting(writable); }); expect(getVisibleChildren(container)).toEqual( @@ -1026,12 +1011,12 @@ describe('ReactDOMFizzServer', () => { await act(async () => { const {startWriting} = ReactDOMFizzServer.renderToNodePipe( , - writable, + { namespaceURI: 'http://www.w3.org/2000/svg', onCompleteShell() { writable.write(''); - startWriting(); + startWriting(writable); writable.write(''); }, }, @@ -1111,11 +1096,8 @@ describe('ReactDOMFizzServer', () => { try { await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( - , - writable, - ); - startWriting(); + const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); + startWriting(writable); }); expect(getVisibleChildren(container)).toEqual( @@ -1224,9 +1206,8 @@ describe('ReactDOMFizzServer', () => { , - writable, ); - startWriting(); + startWriting(writable); }); expect(getVisibleChildren(container)).toEqual(
@@ -1287,9 +1268,8 @@ describe('ReactDOMFizzServer', () => {
, - writable, ); - startWriting(); + startWriting(writable); }); expect(getVisibleChildren(container)).toEqual(
@@ -1355,14 +1335,14 @@ describe('ReactDOMFizzServer', () => {
, - writable, + { onError(x) { loggedErrors.push(x); }, }, ); - startWriting(); + startWriting(writable); }); expect(loggedErrors.length).toBe(1); expect(loggedErrors[0].message).toEqual('A0.1.1'); @@ -1398,14 +1378,14 @@ describe('ReactDOMFizzServer', () => { await act(async () => { controls = ReactDOMFizzServer.renderToNodePipe( , - writable, + { onError(x) { loggedErrors.push(x); }, }, ); - controls.startWriting(); + controls.startWriting(writable); }); // We're still showing a fallback. @@ -1470,9 +1450,8 @@ describe('ReactDOMFizzServer', () => { , - writable, ); - startWriting(); + startWriting(writable); }); expect(getVisibleChildren(container)).toEqual('Loading Outer'); // We should have received a partial segment containing the a partial of the fallback. @@ -1556,9 +1535,8 @@ describe('ReactDOMFizzServer', () => { await act(async () => { const {startWriting} = ReactDOMFizzServer.renderToNodePipe( , - writable, ); - startWriting(); + startWriting(writable); }); // Nothing is output since root has a suspense with avoidedThisFallback that hasn't resolved @@ -1673,14 +1651,14 @@ describe('ReactDOMFizzServer', () => { , - writable, + { onError(x) { loggedErrors.push(x); }, }, ); - startWriting(); + startWriting(writable); }); expect(Scheduler).toHaveYielded(['server']); @@ -1756,14 +1734,14 @@ describe('ReactDOMFizzServer', () => { , - writable, + { onError(x) { loggedErrors.push(x); }, }, ); - startWriting(); + startWriting(writable); }); expect(Scheduler).toHaveYielded(['server']); @@ -1838,11 +1816,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( - , - writable, - ); - startWriting(); + const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); + startWriting(writable); }); expect(Scheduler).toHaveYielded(['Yay!']); @@ -1922,11 +1897,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( - , - writable, - ); - startWriting(); + const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); + startWriting(writable); }); expect(Scheduler).toHaveYielded(['Yay!']); @@ -1997,11 +1969,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( - , - writable, - ); - startWriting(); + const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); + startWriting(writable); }); expect(Scheduler).toHaveYielded(['Yay!']); diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js index dd6aea74b5348..f422a91e29e38 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js @@ -61,9 +61,8 @@ describe('ReactDOMFizzServer', () => { const {writable, output} = getTestWritable(); const {startWriting} = ReactDOMFizzServer.renderToNodePipe(
hello world
, - writable, ); - startWriting(); + startWriting(writable); jest.runAllTimers(); expect(output.result).toMatchInlineSnapshot(`"
hello world
"`); }); @@ -75,9 +74,8 @@ describe('ReactDOMFizzServer', () => { hello world , - writable, ); - startWriting(); + startWriting(writable); jest.runAllTimers(); expect(output.result).toMatchInlineSnapshot( `"hello world"`, @@ -89,14 +87,13 @@ describe('ReactDOMFizzServer', () => { const {writable, output} = getTestWritable(); const {startWriting} = ReactDOMFizzServer.renderToNodePipe(
hello world
, - writable, ); jest.runAllTimers(); // First we write our header. output.result += 'test'; // Then React starts writing. - startWriting(); + startWriting(writable); expect(output.result).toMatchInlineSnapshot( `"test
hello world
"`, ); @@ -121,7 +118,7 @@ describe('ReactDOMFizzServer', () => { , - writable, + { onCompleteAll() { isCompleteCalls++; @@ -144,7 +141,7 @@ describe('ReactDOMFizzServer', () => { output.result += 'test'; // Then React starts writing. - startWriting(); + startWriting(writable); expect(output.result).toMatchInlineSnapshot( `"test
Done
"`, ); @@ -158,7 +155,7 @@ describe('ReactDOMFizzServer', () => {
, - writable, + { onError(x) { reportedErrors.push(x); @@ -167,7 +164,7 @@ describe('ReactDOMFizzServer', () => { ); // The stream is errored once we start writing. - startWriting(); + startWriting(writable); await completed; @@ -187,14 +184,14 @@ describe('ReactDOMFizzServer', () => { , - writable, + { onError(x) { reportedErrors.push(x); }, }, ); - startWriting(); + startWriting(writable); await completed; @@ -213,14 +210,14 @@ describe('ReactDOMFizzServer', () => { , - writable, + { onError(x) { reportedErrors.push(x); }, }, ); - startWriting(); + startWriting(writable); await completed; @@ -246,9 +243,8 @@ describe('ReactDOMFizzServer', () => { }> , - writable, ); - startWriting(); + startWriting(writable); await completed; @@ -267,14 +263,14 @@ describe('ReactDOMFizzServer', () => { , - writable, + { onCompleteAll() { isCompleteCalls++; }, }, ); - startWriting(); + startWriting(writable); jest.runAllTimers(); @@ -302,14 +298,14 @@ describe('ReactDOMFizzServer', () => { , - writable, + { onCompleteAll() { isCompleteCalls++; }, }, ); - startWriting(); + startWriting(writable); jest.runAllTimers(); diff --git a/packages/react-dom/src/server/ReactDOMFizzServerNode.js b/packages/react-dom/src/server/ReactDOMFizzServerNode.js index 6d6bb31e06ade..5d381c268f0f5 100644 --- a/packages/react-dom/src/server/ReactDOMFizzServerNode.js +++ b/packages/react-dom/src/server/ReactDOMFizzServerNode.js @@ -41,7 +41,7 @@ type Controls = {| // Cancel any pending I/O and put anything remaining into // client rendered mode. abort(): void, - startWriting(): void, + startWriting(destination: Writable): void, |}; function createRequestImpl(children: ReactNodeList, options: void | Options) { @@ -58,14 +58,13 @@ function createRequestImpl(children: ReactNodeList, options: void | Options) { function renderToNodePipe( children: ReactNodeList, - destination: Writable, options?: Options, ): Controls { const request = createRequestImpl(children, options); let hasStartedFlowing = false; startWork(request); return { - startWriting() { + startWriting(destination) { if (hasStartedFlowing) { return; } diff --git a/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js b/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js index b9f191a258c9a..192db0fd61cb4 100644 --- a/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js +++ b/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js @@ -26,12 +26,11 @@ type Options = { }; type Controls = {| - startWriting(): void, + startWriting(destination: Writable): void, |}; function renderToNodePipe( model: ReactModel, - destination: Writable, webpackMap: BundlerConfig, options?: Options, ): Controls { @@ -40,11 +39,16 @@ function renderToNodePipe( webpackMap, options ? options.onError : undefined, ); + let hasStartedFlowing = false; startWork(request); - destination.on('drain', createDrainHandler(destination, request)); return { - startWriting() { + startWriting(destination) { + if (hasStartedFlowing) { + return; + } + hasStartedFlowing = true; startFlowing(request, destination); + destination.on('drain', createDrainHandler(destination, request)); }, }; } diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js index 98ade7a7389a8..b158b96cd11e8 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js @@ -57,8 +57,8 @@ describe('ReactFlightDOM', () => { }, }); return { - writable, readable, + writable, }; } @@ -115,10 +115,9 @@ describe('ReactFlightDOM', () => { const {writable, readable} = getTestStream(); const {startWriting} = ReactServerDOMWriter.renderToNodePipe( , - writable, webpackMap, ); - startWriting(); + startWriting(writable); const response = ReactServerDOMReader.createFromReadableStream(readable); await waitForSuspense(() => { const model = response.readRoot(); @@ -169,10 +168,9 @@ describe('ReactFlightDOM', () => { const {writable, readable} = getTestStream(); const {startWriting} = ReactServerDOMWriter.renderToNodePipe( , - writable, webpackMap, ); - startWriting(); + startWriting(writable); const response = ReactServerDOMReader.createFromReadableStream(readable); const container = document.createElement('div'); @@ -208,10 +206,9 @@ describe('ReactFlightDOM', () => { const {writable, readable} = getTestStream(); const {startWriting} = ReactServerDOMWriter.renderToNodePipe( , - writable, webpackMap, ); - startWriting(); + startWriting(writable); const response = ReactServerDOMReader.createFromReadableStream(readable); const container = document.createElement('div'); @@ -245,10 +242,9 @@ describe('ReactFlightDOM', () => { const {writable, readable} = getTestStream(); const {startWriting} = ReactServerDOMWriter.renderToNodePipe( , - writable, webpackMap, ); - startWriting(); + startWriting(writable); const response = ReactServerDOMReader.createFromReadableStream(readable); const container = document.createElement('div'); @@ -381,7 +377,6 @@ describe('ReactFlightDOM', () => { const {writable, readable} = getTestStream(); const {startWriting} = ReactServerDOMWriter.renderToNodePipe( model, - writable, webpackMap, { onError(x) { @@ -389,7 +384,7 @@ describe('ReactFlightDOM', () => { }, }, ); - startWriting(); + startWriting(writable); const response = ReactServerDOMReader.createFromReadableStream(readable); const container = document.createElement('div'); @@ -497,10 +492,9 @@ describe('ReactFlightDOM', () => { const stream1 = getTestStream(); const {startWriting} = ReactServerDOMWriter.renderToNodePipe( , - stream1.writable, webpackMap, ); - startWriting(); + startWriting(stream1.writable); const response1 = ReactServerDOMReader.createFromReadableStream( stream1.readable, ); @@ -526,10 +520,9 @@ describe('ReactFlightDOM', () => { const stream2 = getTestStream(); const {startWriting: startWriting2} = ReactServerDOMWriter.renderToNodePipe( , - stream2.writable, webpackMap, ); - startWriting2(); + startWriting2(stream2.writable); const response2 = ReactServerDOMReader.createFromReadableStream( stream2.readable, );