diff --git a/fixtures/flight/server/handler.server.js b/fixtures/flight/server/handler.server.js
index cd4af7319f01f..b6745c0332791 100644
--- a/fixtures/flight/server/handler.server.js
+++ b/fixtures/flight/server/handler.server.js
@@ -1,6 +1,6 @@
'use strict';
-const {pipeToNodeWritable} = require('react-server-dom-webpack/writer');
+const {renderToPipeableStream} = require('react-server-dom-webpack/writer');
const {readFile} = require('fs');
const {resolve} = require('path');
const React = require('react');
@@ -20,7 +20,11 @@ module.exports = function(req, res) {
const App = m.default.default || m.default;
res.setHeader('Access-Control-Allow-Origin', '*');
const moduleMap = JSON.parse(data);
- pipeToNodeWritable(React.createElement(App), res, moduleMap);
+ const {pipe} = renderToPipeableStream(
+ React.createElement(App),
+ moduleMap
+ );
+ pipe(res);
}
);
});
diff --git a/fixtures/ssr/server/render.js b/fixtures/ssr/server/render.js
index ababbc4ccd72a..e0fc50f3f9538 100644
--- a/fixtures/ssr/server/render.js
+++ b/fixtures/ssr/server/render.js
@@ -1,5 +1,5 @@
import React from 'react';
-import {pipeToNodeWritable} from 'react-dom/server';
+import {renderToPipeableStream} from 'react-dom/server';
import App from '../src/components/App';
@@ -20,22 +20,18 @@ export default function render(url, res) {
console.error('Fatal', error);
});
let didError = false;
- const {startWriting, abort} = pipeToNodeWritable(
- ,
- 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();
- },
- onError(x) {
- didError = true;
- console.error(x);
- },
- }
- );
+ const {pipe, abort} = renderToPipeableStream(, {
+ 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');
+ pipe(res);
+ },
+ onError(x) {
+ didError = true;
+ console.error(x);
+ },
+ });
// Abandon and switch to client rendering after 5 seconds.
// Try lowering this to see the client recover.
setTimeout(abort, 5000);
diff --git a/fixtures/ssr2/server/render.js b/fixtures/ssr2/server/render.js
index b5d919e82ca6d..5ebbed0313c69 100644
--- a/fixtures/ssr2/server/render.js
+++ b/fixtures/ssr2/server/render.js
@@ -8,7 +8,7 @@
import * as React from 'react';
// import {renderToString} from 'react-dom/server';
-import {pipeToNodeWritable} from 'react-dom/server';
+import {renderToPipeableStream} from 'react-dom/server';
import App from '../src/App';
import {DataProvider} from '../src/data';
import {API_DELAY, ABORT_DELAY} from './delays';
@@ -37,17 +37,16 @@ module.exports = function render(url, res) {
});
let didError = false;
const data = createServerData();
- const {startWriting, abort} = pipeToNodeWritable(
+ const {pipe, abort} = renderToPipeableStream(
,
- 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();
+ pipe(res);
},
onError(x) {
didError = true;
diff --git a/packages/react-dom/npm/server.node.js b/packages/react-dom/npm/server.node.js
index e7d3251c4d3dd..2eb97e80354c8 100644
--- a/packages/react-dom/npm/server.node.js
+++ b/packages/react-dom/npm/server.node.js
@@ -14,4 +14,4 @@ exports.renderToString = l.renderToString;
exports.renderToStaticMarkup = l.renderToStaticMarkup;
exports.renderToNodeStream = l.renderToNodeStream;
exports.renderToStaticNodeStream = l.renderToStaticNodeStream;
-exports.pipeToNodeWritable = s.pipeToNodeWritable;
+exports.renderToPipeableStream = s.renderToPipeableStream;
diff --git a/packages/react-dom/server.node.js b/packages/react-dom/server.node.js
index 7fb8cfaeb5a82..1fcab6c8c9ad4 100644
--- a/packages/react-dom/server.node.js
+++ b/packages/react-dom/server.node.js
@@ -36,8 +36,8 @@ export function renderToStaticNodeStream() {
);
}
-export function pipeToNodeWritable() {
- return require('./src/server/ReactDOMFizzServerNode').pipeToNodeWritable.apply(
+export function renderToPipeableStream() {
+ return require('./src/server/ReactDOMFizzServerNode').renderToPipeableStream.apply(
this,
arguments,
);
diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
index d786062043dee..cd0c87a1df3b2 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.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
@@ -304,16 +303,16 @@ describe('ReactDOMFizzServer', () => {
}
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
+
{
onError(x) {
loggedErrors.push(x);
},
},
);
- startWriting();
+ pipe(writable);
});
expect(loggedErrors).toEqual([]);
@@ -356,15 +355,14 @@ describe('ReactDOMFizzServer', () => {
});
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
}>
{lazyElement}
,
- writable,
);
- startWriting();
+ pipe(writable);
});
expect(getVisibleChildren(container)).toEqual(
Loading...
);
await act(async () => {
@@ -396,16 +394,16 @@ describe('ReactDOMFizzServer', () => {
}
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
+
{
onError(x) {
loggedErrors.push(x);
},
},
);
- startWriting();
+ pipe(writable);
});
expect(loggedErrors).toEqual([]);
@@ -441,15 +439,14 @@ describe('ReactDOMFizzServer', () => {
// @gate experimental
it('should asynchronously load the suspense boundary', async () => {
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
);
- startWriting();
+ pipe(writable);
});
expect(getVisibleChildren(container)).toEqual(
Loading...
);
await act(async () => {
@@ -475,11 +472,8 @@ describe('ReactDOMFizzServer', () => {
}
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
-
,
- writable,
- );
- startWriting();
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
);
+ pipe(writable);
});
// We're still showing a fallback.
@@ -550,16 +544,16 @@ describe('ReactDOMFizzServer', () => {
// We originally suspend the boundary and start streaming the loading state.
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
+
{
onError(x) {
loggedErrors.push(x);
},
},
);
- startWriting();
+ pipe(writable);
});
// We're still showing a fallback.
@@ -633,11 +627,10 @@ describe('ReactDOMFizzServer', () => {
// We originally suspend the boundary and start streaming the loading state.
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
);
- startWriting();
+ pipe(writable);
});
const root = ReactDOM.createRoot(container, {hydrate: true});
@@ -701,8 +694,8 @@ describe('ReactDOMFizzServer', () => {
let controls;
await act(async () => {
- controls = ReactDOMFizzServer.pipeToNodeWritable(
, writable);
- controls.startWriting();
+ controls = ReactDOMFizzServer.renderToPipeableStream(
);
+ controls.pipe(writable);
});
// We're still showing a fallback.
@@ -753,7 +746,7 @@ describe('ReactDOMFizzServer', () => {
};
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
// We use two nested boundaries to flush out coverage of an old reentrancy bug.
}>
@@ -765,12 +758,11 @@ describe('ReactDOMFizzServer', () => {
>
,
- writableA,
{
identifierPrefix: 'A_',
onCompleteShell() {
writableA.write('
');
- startWriting();
+ pipe(writableA);
writableA.write('
');
},
},
@@ -778,19 +770,18 @@ describe('ReactDOMFizzServer', () => {
});
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
}>
,
- writableB,
{
identifierPrefix: 'B_',
onCompleteShell() {
writableB.write('
');
- startWriting();
+ pipe(writableB);
writableB.write('
');
},
},
@@ -876,11 +867,8 @@ describe('ReactDOMFizzServer', () => {
}
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
-
,
- writable,
- );
- startWriting();
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
);
+ pipe(writable);
});
expect(getVisibleChildren(container)).toEqual(
@@ -967,11 +955,8 @@ describe('ReactDOMFizzServer', () => {
}
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
-
,
- writable,
- );
- startWriting();
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
);
+ pipe(writable);
});
expect(getVisibleChildren(container)).toEqual(
@@ -1024,14 +1009,14 @@ describe('ReactDOMFizzServer', () => {
}
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
+
{
namespaceURI: 'http://www.w3.org/2000/svg',
onCompleteShell() {
writable.write('
');
},
},
@@ -1111,11 +1096,8 @@ describe('ReactDOMFizzServer', () => {
try {
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
-
,
- writable,
- );
- startWriting();
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
);
+ pipe(writable);
});
expect(getVisibleChildren(container)).toEqual(
@@ -1213,7 +1195,7 @@ describe('ReactDOMFizzServer', () => {
}
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
, ]}>
@@ -1224,9 +1206,8 @@ describe('ReactDOMFizzServer', () => {
,
- writable,
);
- startWriting();
+ pipe(writable);
});
expect(getVisibleChildren(container)).toEqual(
@@ -1272,7 +1253,7 @@ describe('ReactDOMFizzServer', () => {
}
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
@@ -1287,9 +1268,8 @@ describe('ReactDOMFizzServer', () => {
,
- writable,
);
- startWriting();
+ pipe(writable);
});
expect(getVisibleChildren(container)).toEqual(
@@ -1335,7 +1315,7 @@ describe('ReactDOMFizzServer', () => {
const loggedErrors = [];
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
@@ -1355,14 +1335,14 @@ describe('ReactDOMFizzServer', () => {
,
- writable,
+
{
onError(x) {
loggedErrors.push(x);
},
},
);
- startWriting();
+ pipe(writable);
});
expect(loggedErrors.length).toBe(1);
expect(loggedErrors[0].message).toEqual('A0.1.1');
@@ -1396,16 +1376,16 @@ describe('ReactDOMFizzServer', () => {
const loggedErrors = [];
let controls;
await act(async () => {
- controls = ReactDOMFizzServer.pipeToNodeWritable(
+ controls = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
+
{
onError(x) {
loggedErrors.push(x);
},
},
);
- controls.startWriting();
+ controls.pipe(writable);
});
// We're still showing a fallback.
@@ -1456,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.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
}>
{
,
- writable,
);
- startWriting();
+ pipe(writable);
});
expect(getVisibleChildren(container)).toEqual('Loading Outer');
// We should have received a partial segment containing the a partial of the fallback.
@@ -1554,11 +1533,10 @@ describe('ReactDOMFizzServer', () => {
await jest.runAllTimers();
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
);
- startWriting();
+ pipe(writable);
});
// Nothing is output since root has a suspense with avoidedThisFallback that hasn't resolved
@@ -1669,18 +1647,18 @@ describe('ReactDOMFizzServer', () => {
const loggedErrors = [];
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
+
{
onError(x) {
loggedErrors.push(x);
},
},
);
- startWriting();
+ pipe(writable);
});
expect(Scheduler).toHaveYielded(['server']);
@@ -1752,18 +1730,18 @@ describe('ReactDOMFizzServer', () => {
const loggedErrors = [];
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
+
{
onError(x) {
loggedErrors.push(x);
},
},
);
- startWriting();
+ pipe(writable);
});
expect(Scheduler).toHaveYielded(['server']);
@@ -1838,11 +1816,8 @@ describe('ReactDOMFizzServer', () => {
}
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
-
,
- writable,
- );
- startWriting();
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
);
+ pipe(writable);
});
expect(Scheduler).toHaveYielded(['Yay!']);
@@ -1922,11 +1897,8 @@ describe('ReactDOMFizzServer', () => {
}
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
-
,
- writable,
- );
- startWriting();
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
);
+ pipe(writable);
});
expect(Scheduler).toHaveYielded(['Yay!']);
@@ -1997,11 +1969,8 @@ describe('ReactDOMFizzServer', () => {
}
await act(async () => {
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
-
,
- writable,
- );
- startWriting();
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
);
+ 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 949ddcb04fa2d..7fa1c208dffc9 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
@@ -57,13 +57,12 @@ describe('ReactDOMFizzServer', () => {
}
// @gate experimental
- it('should call pipeToNodeWritable', () => {
+ it('should call renderToPipeableStream', () => {
const {writable, output} = getTestWritable();
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
hello world
,
- writable,
);
- startWriting();
+ pipe(writable);
jest.runAllTimers();
expect(output.result).toMatchInlineSnapshot(`"
hello world
"`);
});
@@ -71,13 +70,12 @@ describe('ReactDOMFizzServer', () => {
// @gate experimental
it('should emit DOCTYPE at the root of the document', () => {
const {writable, output} = getTestWritable();
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
hello world
,
- writable,
);
- startWriting();
+ pipe(writable);
jest.runAllTimers();
expect(output.result).toMatchInlineSnapshot(
`"hello world"`,
@@ -85,18 +83,17 @@ describe('ReactDOMFizzServer', () => {
});
// @gate experimental
- it('should start writing after startWriting', () => {
+ it('should start writing after pipe', () => {
const {writable, output} = getTestWritable();
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
hello world
,
- writable,
);
jest.runAllTimers();
// First we write our header.
output.result +=
'
test';
// Then React starts writing.
- startWriting();
+ pipe(writable);
expect(output.result).toMatchInlineSnapshot(
`"
testhello world
"`,
);
@@ -115,13 +112,13 @@ describe('ReactDOMFizzServer', () => {
}
let isCompleteCalls = 0;
const {writable, output} = getTestWritable();
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
+
{
onCompleteAll() {
isCompleteCalls++;
@@ -144,7 +141,7 @@ describe('ReactDOMFizzServer', () => {
output.result +=
'
test';
// Then React starts writing.
- startWriting();
+ pipe(writable);
expect(output.result).toMatchInlineSnapshot(
`"
testDone
"`,
);
@@ -154,11 +151,11 @@ 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.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
,
- writable,
+
{
onError(x) {
reportedErrors.push(x);
@@ -167,7 +164,7 @@ describe('ReactDOMFizzServer', () => {
);
// The stream is errored once we start writing.
- startWriting();
+ pipe(writable);
await completed;
@@ -181,20 +178,20 @@ 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.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
}>
,
- writable,
+
{
onError(x) {
reportedErrors.push(x);
},
},
);
- startWriting();
+ pipe(writable);
await completed;
@@ -207,20 +204,20 @@ 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.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
Loading
}>
,
- writable,
+
{
onError(x) {
reportedErrors.push(x);
},
},
);
- startWriting();
+ pipe(writable);
await completed;
@@ -242,13 +239,12 @@ describe('ReactDOMFizzServer', () => {
function Content() {
return 'Hi';
}
- const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+ const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
}>
,
- writable,
);
- startWriting();
+ pipe(writable);
await completed;
@@ -261,20 +257,20 @@ 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.pipeToNodeWritable(
+ const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream(
Loading
}>
,
- writable,
+
{
onCompleteAll() {
isCompleteCalls++;
},
},
);
- startWriting();
+ pipe(writable);
jest.runAllTimers();
@@ -294,7 +290,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.pipeToNodeWritable(
+ const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream(
}>
@@ -302,14 +298,14 @@ describe('ReactDOMFizzServer', () => {
,
- writable,
+
{
onCompleteAll() {
isCompleteCalls++;
},
},
);
- startWriting();
+ pipe(writable);
jest.runAllTimers();
diff --git a/packages/react-dom/src/server/ReactDOMFizzServerNode.js b/packages/react-dom/src/server/ReactDOMFizzServerNode.js
index fb1939f0c404f..4233a88e1fb94 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,
+ pipe
(destination: T): T,
|};
function createRequestImpl(children: ReactNodeList, options: void | Options) {
@@ -56,22 +56,24 @@ function createRequestImpl(children: ReactNodeList, options: void | Options) {
);
}
-function pipeToNodeWritable(
+function renderToPipeableStream(
children: ReactNodeList,
- destination: Writable,
options?: Options,
): Controls {
const request = createRequestImpl(children, options);
let hasStartedFlowing = false;
startWork(request);
return {
- startWriting() {
+ 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);
@@ -79,4 +81,4 @@ function pipeToNodeWritable(
};
}
-export {pipeToNodeWritable, ReactVersion as version};
+export {renderToPipeableStream, ReactVersion as version};
diff --git a/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js b/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js
index 35773279890ca..5f992d4b03e9b 100644
--- a/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js
+++ b/packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js
@@ -25,20 +25,35 @@ type Options = {
onError?: (error: mixed) => void,
};
-function pipeToNodeWritable(
+type Controls = {|
+ pipe(destination: T): T,
+|};
+
+function renderToPipeableStream(
model: ReactModel,
- destination: Writable,
webpackMap: BundlerConfig,
options?: Options,
-): void {
+): Controls {
const request = createRequest(
model,
webpackMap,
options ? options.onError : undefined,
);
+ let hasStartedFlowing = false;
startWork(request);
- startFlowing(request, destination);
- destination.on('drain', createDrainHandler(destination, request));
+ return {
+ pipe(destination: T): T {
+ if (hasStartedFlowing) {
+ 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;
+ },
+ };
}
-export {pipeToNodeWritable};
+export {renderToPipeableStream};
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 60fbac215f73d..bcae6c50f7c7f 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,
};
}
@@ -113,7 +113,11 @@ describe('ReactFlightDOM', () => {
}
const {writable, readable} = getTestStream();
- ReactServerDOMWriter.pipeToNodeWritable(, writable, webpackMap);
+ const {pipe} = ReactServerDOMWriter.renderToPipeableStream(
+ ,
+ webpackMap,
+ );
+ pipe(writable);
const response = ReactServerDOMReader.createFromReadableStream(readable);
await waitForSuspense(() => {
const model = response.readRoot();
@@ -162,11 +166,11 @@ describe('ReactFlightDOM', () => {
}
const {writable, readable} = getTestStream();
- ReactServerDOMWriter.pipeToNodeWritable(
+ const {pipe} = ReactServerDOMWriter.renderToPipeableStream(
,
- writable,
webpackMap,
);
+ pipe(writable);
const response = ReactServerDOMReader.createFromReadableStream(readable);
const container = document.createElement('div');
@@ -200,11 +204,11 @@ describe('ReactFlightDOM', () => {
}
const {writable, readable} = getTestStream();
- ReactServerDOMWriter.pipeToNodeWritable(
+ const {pipe} = ReactServerDOMWriter.renderToPipeableStream(
,
- writable,
webpackMap,
);
+ pipe(writable);
const response = ReactServerDOMReader.createFromReadableStream(readable);
const container = document.createElement('div');
@@ -236,11 +240,11 @@ describe('ReactFlightDOM', () => {
}
const {writable, readable} = getTestStream();
- ReactServerDOMWriter.pipeToNodeWritable(
+ const {pipe} = ReactServerDOMWriter.renderToPipeableStream(
,
- writable,
webpackMap,
);
+ pipe(writable);
const response = ReactServerDOMReader.createFromReadableStream(readable);
const container = document.createElement('div');
@@ -371,11 +375,16 @@ describe('ReactFlightDOM', () => {
}
const {writable, readable} = getTestStream();
- ReactServerDOMWriter.pipeToNodeWritable(model, writable, webpackMap, {
- onError(x) {
- reportedErrors.push(x);
+ const {pipe} = ReactServerDOMWriter.renderToPipeableStream(
+ model,
+ webpackMap,
+ {
+ onError(x) {
+ reportedErrors.push(x);
+ },
},
- });
+ );
+ pipe(writable);
const response = ReactServerDOMReader.createFromReadableStream(readable);
const container = document.createElement('div');
@@ -481,11 +490,11 @@ describe('ReactFlightDOM', () => {
const root = ReactDOM.createRoot(container);
const stream1 = getTestStream();
- ReactServerDOMWriter.pipeToNodeWritable(
+ const {pipe} = ReactServerDOMWriter.renderToPipeableStream(
,
- stream1.writable,
webpackMap,
);
+ pipe(stream1.writable);
const response1 = ReactServerDOMReader.createFromReadableStream(
stream1.readable,
);
@@ -509,11 +518,11 @@ describe('ReactFlightDOM', () => {
inputB.value = 'goodbye';
const stream2 = getTestStream();
- ReactServerDOMWriter.pipeToNodeWritable(
+ const {pipe: pipe2} = ReactServerDOMWriter.renderToPipeableStream(
,
- stream2.writable,
webpackMap,
);
+ pipe2(stream2.writable);
const response2 = ReactServerDOMReader.createFromReadableStream(
stream2.readable,
);
diff --git a/scripts/error-codes/codes.json b/scripts/error-codes/codes.json
index d1688e84bc7a8..aab5d62476cc3 100644
--- a/scripts/error-codes/codes.json
+++ b/scripts/error-codes/codes.json
@@ -401,5 +401,6 @@
"413": "Expected finished root and lanes to be set. This is a bug in React.",
"414": "Did not expect this call in production. This is a bug in React. Please file an issue.",
"415": "Error parsing the data. It's probably an error code or network corruption.",
- "416": "This environment don't support binary chunks."
+ "416": "This environment don't support binary chunks.",
+ "417": "React currently only supports piping to one writable stream."
}