diff --git a/fixtures/flight/server/handler.server.js b/fixtures/flight/server/handler.server.js index f695f0366e70a..e9cd851255e07 100644 --- a/fixtures/flight/server/handler.server.js +++ b/fixtures/flight/server/handler.server.js @@ -20,11 +20,8 @@ module.exports = function(req, res) { const App = m.default.default || m.default; res.setHeader('Access-Control-Allow-Origin', '*'); const moduleMap = JSON.parse(data); - const {startWriting} = renderToNodePipe( - React.createElement(App), - moduleMap - ); - startWriting(res); + const {pipe} = renderToNodePipe(React.createElement(App), moduleMap); + pipe(res); } ); }); diff --git a/fixtures/ssr/server/render.js b/fixtures/ssr/server/render.js index 63a795718cc7b..9beb68111d0d7 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(, { + const {pipe, 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(res); + pipe(res); }, onError(x) { didError = true; diff --git a/fixtures/ssr2/server/render.js b/fixtures/ssr2/server/render.js index aa17e1121b0e0..97ef239183491 100644 --- a/fixtures/ssr2/server/render.js +++ b/fixtures/ssr2/server/render.js @@ -37,7 +37,7 @@ module.exports = function render(url, res) { }); let didError = false; const data = createServerData(); - const {startWriting, abort} = renderToNodePipe( + const {pipe, abort} = renderToNodePipe( , @@ -46,7 +46,7 @@ module.exports = function render(url, res) { // 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(res); + pipe(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 bc5d127c35184..a42589d8ab1d8 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -239,7 +239,7 @@ describe('ReactDOMFizzServer', () => { }; await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
}> @@ -253,7 +253,7 @@ describe('ReactDOMFizzServer', () => {
, ); - startWriting(writable); + pipe(writable); }); expect(getVisibleChildren(container)).toEqual(
@@ -303,7 +303,7 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( , { @@ -312,7 +312,7 @@ describe('ReactDOMFizzServer', () => { }, }, ); - startWriting(writable); + pipe(writable); }); expect(loggedErrors).toEqual([]); @@ -355,14 +355,14 @@ describe('ReactDOMFizzServer', () => { }); await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
}> {lazyElement}
, ); - startWriting(writable); + pipe(writable); }); expect(getVisibleChildren(container)).toEqual(
Loading...
); await act(async () => { @@ -394,7 +394,7 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( , { @@ -403,7 +403,7 @@ describe('ReactDOMFizzServer', () => { }, }, ); - startWriting(writable); + pipe(writable); }); expect(loggedErrors).toEqual([]); @@ -439,14 +439,14 @@ describe('ReactDOMFizzServer', () => { // @gate experimental it('should asynchronously load the suspense boundary', async () => { await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
}>
, ); - startWriting(writable); + pipe(writable); }); expect(getVisibleChildren(container)).toEqual(
Loading...
); await act(async () => { @@ -472,8 +472,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); - startWriting(writable); + const {pipe} = ReactDOMFizzServer.renderToNodePipe(); + pipe(writable); }); // We're still showing a fallback. @@ -544,7 +544,7 @@ describe('ReactDOMFizzServer', () => { // We originally suspend the boundary and start streaming the loading state. await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( , { @@ -553,7 +553,7 @@ describe('ReactDOMFizzServer', () => { }, }, ); - startWriting(writable); + pipe(writable); }); // We're still showing a fallback. @@ -627,10 +627,10 @@ describe('ReactDOMFizzServer', () => { // We originally suspend the boundary and start streaming the loading state. await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( , ); - startWriting(writable); + pipe(writable); }); const root = ReactDOM.createRoot(container, {hydrate: true}); @@ -695,7 +695,7 @@ describe('ReactDOMFizzServer', () => { let controls; await act(async () => { controls = ReactDOMFizzServer.renderToNodePipe(); - controls.startWriting(writable); + controls.pipe(writable); }); // We're still showing a fallback. @@ -746,7 +746,7 @@ describe('ReactDOMFizzServer', () => { }; await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( // We use two nested boundaries to flush out coverage of an old reentrancy bug. }> @@ -762,7 +762,7 @@ describe('ReactDOMFizzServer', () => { identifierPrefix: 'A_', onCompleteShell() { writableA.write('
'); - startWriting(writableA); + pipe(writableA); writableA.write('
'); }, }, @@ -770,7 +770,7 @@ describe('ReactDOMFizzServer', () => { }); await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( }>
@@ -781,7 +781,7 @@ describe('ReactDOMFizzServer', () => { identifierPrefix: 'B_', onCompleteShell() { writableB.write('
'); - startWriting(writableB); + pipe(writableB); writableB.write('
'); }, }, @@ -867,8 +867,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); - startWriting(writable); + const {pipe} = ReactDOMFizzServer.renderToNodePipe(); + pipe(writable); }); expect(getVisibleChildren(container)).toEqual( @@ -955,8 +955,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); - startWriting(writable); + const {pipe} = ReactDOMFizzServer.renderToNodePipe(); + pipe(writable); }); expect(getVisibleChildren(container)).toEqual( @@ -1009,14 +1009,14 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( , { namespaceURI: 'http://www.w3.org/2000/svg', onCompleteShell() { writable.write(''); - startWriting(writable); + pipe(writable); writable.write(''); }, }, @@ -1096,8 +1096,8 @@ describe('ReactDOMFizzServer', () => { try { await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); - startWriting(writable); + const {pipe} = ReactDOMFizzServer.renderToNodePipe(); + pipe(writable); }); expect(getVisibleChildren(container)).toEqual( @@ -1195,7 +1195,7 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
, ]}> @@ -1207,7 +1207,7 @@ describe('ReactDOMFizzServer', () => {
, ); - startWriting(writable); + pipe(writable); }); expect(getVisibleChildren(container)).toEqual(
@@ -1253,7 +1253,7 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
@@ -1269,7 +1269,7 @@ describe('ReactDOMFizzServer', () => {
, ); - startWriting(writable); + pipe(writable); }); expect(getVisibleChildren(container)).toEqual(
@@ -1315,7 +1315,7 @@ describe('ReactDOMFizzServer', () => { const loggedErrors = []; await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
@@ -1342,7 +1342,7 @@ describe('ReactDOMFizzServer', () => { }, }, ); - startWriting(writable); + pipe(writable); }); expect(loggedErrors.length).toBe(1); expect(loggedErrors[0].message).toEqual('A0.1.1'); @@ -1385,7 +1385,7 @@ describe('ReactDOMFizzServer', () => { }, }, ); - controls.startWriting(writable); + controls.pipe(writable); }); // We're still showing a fallback. @@ -1436,7 +1436,7 @@ describe('ReactDOMFizzServer', () => { // @gate experimental it('should be able to abort the fallback if the main content finishes first', async () => { await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( }>
{
, ); - startWriting(writable); + pipe(writable); }); expect(getVisibleChildren(container)).toEqual('Loading Outer'); // We should have received a partial segment containing the a partial of the fallback. @@ -1533,10 +1533,10 @@ describe('ReactDOMFizzServer', () => { await jest.runAllTimers(); await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( , ); - startWriting(writable); + pipe(writable); }); // Nothing is output since root has a suspense with avoidedThisFallback that hasn't resolved @@ -1647,7 +1647,7 @@ describe('ReactDOMFizzServer', () => { const loggedErrors = []; await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( , @@ -1658,7 +1658,7 @@ describe('ReactDOMFizzServer', () => { }, }, ); - startWriting(writable); + pipe(writable); }); expect(Scheduler).toHaveYielded(['server']); @@ -1730,7 +1730,7 @@ describe('ReactDOMFizzServer', () => { const loggedErrors = []; await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( , @@ -1741,7 +1741,7 @@ describe('ReactDOMFizzServer', () => { }, }, ); - startWriting(writable); + pipe(writable); }); expect(Scheduler).toHaveYielded(['server']); @@ -1816,8 +1816,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); - startWriting(writable); + const {pipe} = ReactDOMFizzServer.renderToNodePipe(); + pipe(writable); }); expect(Scheduler).toHaveYielded(['Yay!']); @@ -1897,8 +1897,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); - startWriting(writable); + const {pipe} = ReactDOMFizzServer.renderToNodePipe(); + pipe(writable); }); expect(Scheduler).toHaveYielded(['Yay!']); @@ -1969,8 +1969,8 @@ describe('ReactDOMFizzServer', () => { } await act(async () => { - const {startWriting} = ReactDOMFizzServer.renderToNodePipe(); - startWriting(writable); + const {pipe} = ReactDOMFizzServer.renderToNodePipe(); + pipe(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 f422a91e29e38..dc9d515736d1a 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js @@ -59,10 +59,8 @@ describe('ReactDOMFizzServer', () => { // @gate experimental it('should call renderToNodePipe', () => { const {writable, output} = getTestWritable(); - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( -
hello world
, - ); - startWriting(writable); + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
hello world
); + pipe(writable); jest.runAllTimers(); expect(output.result).toMatchInlineSnapshot(`"
hello world
"`); }); @@ -70,12 +68,12 @@ describe('ReactDOMFizzServer', () => { // @gate experimental it('should emit DOCTYPE at the root of the document', () => { const {writable, output} = getTestWritable(); - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( hello world , ); - startWriting(writable); + pipe(writable); jest.runAllTimers(); expect(output.result).toMatchInlineSnapshot( `"hello world"`, @@ -83,17 +81,15 @@ describe('ReactDOMFizzServer', () => { }); // @gate experimental - it('should start writing after startWriting', () => { + it('should start writing after pipe', () => { const {writable, output} = getTestWritable(); - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( -
hello world
, - ); + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
hello world
); jest.runAllTimers(); // First we write our header. output.result += 'test'; // Then React starts writing. - startWriting(writable); + pipe(writable); expect(output.result).toMatchInlineSnapshot( `"test
hello world
"`, ); @@ -112,7 +108,7 @@ describe('ReactDOMFizzServer', () => { } let isCompleteCalls = 0; const {writable, output} = getTestWritable(); - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
@@ -141,7 +137,7 @@ describe('ReactDOMFizzServer', () => { output.result += 'test'; // Then React starts writing. - startWriting(writable); + pipe(writable); expect(output.result).toMatchInlineSnapshot( `"test
Done
"`, ); @@ -151,7 +147,7 @@ describe('ReactDOMFizzServer', () => { it('should error the stream when an error is thrown at the root', async () => { const reportedErrors = []; const {writable, output, completed} = getTestWritable(); - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
, @@ -164,7 +160,7 @@ describe('ReactDOMFizzServer', () => { ); // The stream is errored once we start writing. - startWriting(writable); + pipe(writable); await completed; @@ -178,7 +174,7 @@ describe('ReactDOMFizzServer', () => { it('should error the stream when an error is thrown inside a fallback', async () => { const reportedErrors = []; const {writable, output, completed} = getTestWritable(); - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
}> @@ -191,7 +187,7 @@ describe('ReactDOMFizzServer', () => { }, }, ); - startWriting(writable); + pipe(writable); await completed; @@ -204,7 +200,7 @@ describe('ReactDOMFizzServer', () => { it('should not error the stream when an error is thrown inside suspense boundary', async () => { const reportedErrors = []; const {writable, output, completed} = getTestWritable(); - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe(
Loading
}> @@ -217,7 +213,7 @@ describe('ReactDOMFizzServer', () => { }, }, ); - startWriting(writable); + pipe(writable); await completed; @@ -239,12 +235,12 @@ describe('ReactDOMFizzServer', () => { function Content() { return 'Hi'; } - const {startWriting} = ReactDOMFizzServer.renderToNodePipe( + const {pipe} = ReactDOMFizzServer.renderToNodePipe( }> , ); - startWriting(writable); + pipe(writable); await completed; @@ -257,7 +253,7 @@ describe('ReactDOMFizzServer', () => { it('should be able to complete by aborting even if the promise never resolves', async () => { let isCompleteCalls = 0; const {writable, output, completed} = getTestWritable(); - const {startWriting, abort} = ReactDOMFizzServer.renderToNodePipe( + const {pipe, abort} = ReactDOMFizzServer.renderToNodePipe(
Loading
}> @@ -270,7 +266,7 @@ describe('ReactDOMFizzServer', () => { }, }, ); - startWriting(writable); + pipe(writable); jest.runAllTimers(); @@ -290,7 +286,7 @@ describe('ReactDOMFizzServer', () => { it('should be able to complete by abort when the fallback is also suspended', async () => { let isCompleteCalls = 0; const {writable, output, completed} = getTestWritable(); - const {startWriting, abort} = ReactDOMFizzServer.renderToNodePipe( + const {pipe, abort} = ReactDOMFizzServer.renderToNodePipe(
}> @@ -305,7 +301,7 @@ describe('ReactDOMFizzServer', () => { }, }, ); - startWriting(writable); + pipe(writable); jest.runAllTimers(); diff --git a/packages/react-dom/src/server/ReactDOMFizzServerNode.js b/packages/react-dom/src/server/ReactDOMFizzServerNode.js index 5d381c268f0f5..9b4b74666b182 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(destination: Writable): void, + pipe(destination: T): T, |}; function createRequestImpl(children: ReactNodeList, options: void | Options) { @@ -64,13 +64,16 @@ function renderToNodePipe( let hasStartedFlowing = false; startWork(request); return { - startWriting(destination) { + pipe(destination: T): T { if (hasStartedFlowing) { - return; + throw new Error( + 'React currently only supports piping to one writable stream', + ); } hasStartedFlowing = true; startFlowing(request, destination); destination.on('drain', createDrainHandler(destination, request)); + return destination; }, abort() { abort(request); diff --git a/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js b/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js index 192db0fd61cb4..e0103bd1ed15b 100644 --- a/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js +++ b/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js @@ -26,7 +26,7 @@ type Options = { }; type Controls = {| - startWriting(destination: Writable): void, + pipe(destination: T): T, |}; function renderToNodePipe( @@ -42,13 +42,16 @@ function renderToNodePipe( let hasStartedFlowing = false; startWork(request); return { - startWriting(destination) { + pipe(destination: T): T { if (hasStartedFlowing) { - return; + throw new Error( + 'React currently only supports piping to one writable stream', + ); } hasStartedFlowing = true; startFlowing(request, destination); destination.on('drain', createDrainHandler(destination, request)); + return destination; }, }; } 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 b158b96cd11e8..a129334507569 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js @@ -113,11 +113,8 @@ describe('ReactFlightDOM', () => { } const {writable, readable} = getTestStream(); - const {startWriting} = ReactServerDOMWriter.renderToNodePipe( - , - webpackMap, - ); - startWriting(writable); + const {pipe} = ReactServerDOMWriter.renderToNodePipe(, webpackMap); + pipe(writable); const response = ReactServerDOMReader.createFromReadableStream(readable); await waitForSuspense(() => { const model = response.readRoot(); @@ -166,11 +163,11 @@ describe('ReactFlightDOM', () => { } const {writable, readable} = getTestStream(); - const {startWriting} = ReactServerDOMWriter.renderToNodePipe( + const {pipe} = ReactServerDOMWriter.renderToNodePipe( , webpackMap, ); - startWriting(writable); + pipe(writable); const response = ReactServerDOMReader.createFromReadableStream(readable); const container = document.createElement('div'); @@ -204,11 +201,11 @@ describe('ReactFlightDOM', () => { } const {writable, readable} = getTestStream(); - const {startWriting} = ReactServerDOMWriter.renderToNodePipe( + const {pipe} = ReactServerDOMWriter.renderToNodePipe( , webpackMap, ); - startWriting(writable); + pipe(writable); const response = ReactServerDOMReader.createFromReadableStream(readable); const container = document.createElement('div'); @@ -240,11 +237,11 @@ describe('ReactFlightDOM', () => { } const {writable, readable} = getTestStream(); - const {startWriting} = ReactServerDOMWriter.renderToNodePipe( + const {pipe} = ReactServerDOMWriter.renderToNodePipe( , webpackMap, ); - startWriting(writable); + pipe(writable); const response = ReactServerDOMReader.createFromReadableStream(readable); const container = document.createElement('div'); @@ -375,16 +372,12 @@ describe('ReactFlightDOM', () => { } const {writable, readable} = getTestStream(); - const {startWriting} = ReactServerDOMWriter.renderToNodePipe( - model, - webpackMap, - { - onError(x) { - reportedErrors.push(x); - }, + const {pipe} = ReactServerDOMWriter.renderToNodePipe(model, webpackMap, { + onError(x) { + reportedErrors.push(x); }, - ); - startWriting(writable); + }); + pipe(writable); const response = ReactServerDOMReader.createFromReadableStream(readable); const container = document.createElement('div'); @@ -490,11 +483,11 @@ describe('ReactFlightDOM', () => { const root = ReactDOM.createRoot(container); const stream1 = getTestStream(); - const {startWriting} = ReactServerDOMWriter.renderToNodePipe( + const {pipe} = ReactServerDOMWriter.renderToNodePipe( , webpackMap, ); - startWriting(stream1.writable); + pipe(stream1.writable); const response1 = ReactServerDOMReader.createFromReadableStream( stream1.readable, ); @@ -518,11 +511,11 @@ describe('ReactFlightDOM', () => { inputB.value = 'goodbye'; const stream2 = getTestStream(); - const {startWriting: startWriting2} = ReactServerDOMWriter.renderToNodePipe( + const {pipe: pipe2} = ReactServerDOMWriter.renderToNodePipe( , webpackMap, ); - startWriting2(stream2.writable); + pipe2(stream2.writable); const response2 = ReactServerDOMReader.createFromReadableStream( stream2.readable, );