Revert Node Web Streams (#33472)

Reverts #33457, #33456 and #33442.

There are too many issues with wrappers, lazy init, stateful modules,
duplicate instantiation of async_hooks and duplication of code.

Instead, we'll just do a wrapper polyfill that uses Node Streams
internally.

I kept the client indirection files that I added for consistency with
the server though.
This commit is contained in:
Sebastian Markbåge
2025-06-06 16:26:36 -04:00
committed by GitHub
parent 142aa0744d
commit 82f3684c63
33 changed files with 19 additions and 977 deletions
@@ -1,18 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export {default as rendererVersion} from 'shared/ReactVersion';
export const rendererPackageName = 'react-server-dom-parcel';
export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
export * from 'react-client/src/ReactClientConsoleConfigServer';
export * from 'react-server-dom-parcel/src/client/ReactFlightClientConfigBundlerParcel';
export * from 'react-server-dom-parcel/src/client/ReactFlightClientConfigTargetParcelServer';
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
export const usedWithSSR = true;
@@ -1,19 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export {default as rendererVersion} from 'shared/ReactVersion';
export const rendererPackageName = 'react-server-dom-turbopack';
export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
export * from 'react-client/src/ReactClientConsoleConfigServer';
export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack';
export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopackServer';
export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigTargetTurbopackServer';
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
export const usedWithSSR = true;
@@ -1,19 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export {default as rendererVersion} from 'shared/ReactVersion';
export const rendererPackageName = 'react-server-dom-webpack';
export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
export * from 'react-client/src/ReactClientConsoleConfigServer';
export * from 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack';
export * from 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpackServer';
export * from 'react-server-dom-webpack/src/client/ReactFlightClientConfigTargetWebpackServer';
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
export const usedWithSSR = true;
@@ -1,18 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export {default as rendererVersion} from 'shared/ReactVersion';
export const rendererPackageName = 'react-server-dom-webpack';
export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
export * from 'react-client/src/ReactClientConsoleConfigServer';
export * from 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerNode';
export * from 'react-server-dom-webpack/src/client/ReactFlightClientConfigTargetWebpackServer';
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
export const usedWithSSR = true;
+1 -7
View File
@@ -1,14 +1,12 @@
'use strict';
var l, s, w;
var l, s;
if (process.env.NODE_ENV === 'production') {
l = require('./cjs/react-dom-server-legacy.node.production.js');
s = require('./cjs/react-dom-server.node.production.js');
w = require('./cjs/react-dom-server.node-webstreams.production.js');
} else {
l = require('./cjs/react-dom-server-legacy.node.development.js');
s = require('./cjs/react-dom-server.node.development.js');
w = require('./cjs/react-dom-server.node-webstreams.development.js');
}
exports.version = l.version;
@@ -18,7 +16,3 @@ exports.renderToPipeableStream = s.renderToPipeableStream;
if (s.resumeToPipeableStream) {
exports.resumeToPipeableStream = s.resumeToPipeableStream;
}
exports.renderToReadableStream = w.renderToReadableStream;
if (w.resume) {
exports.resume = w.resume;
}
+1 -5
View File
@@ -1,16 +1,12 @@
'use strict';
var s, w;
var s;
if (process.env.NODE_ENV === 'production') {
s = require('./cjs/react-dom-server.node.production.js');
w = require('./cjs/react-dom-server.node-webstreams.production.js');
} else {
s = require('./cjs/react-dom-server.node.development.js');
w = require('./cjs/react-dom-server.node-webstreams.development.js');
}
exports.version = s.version;
exports.prerenderToNodeStream = s.prerenderToNodeStream;
exports.resumeAndPrerenderToNodeStream = s.resumeAndPrerenderToNodeStream;
exports.prerender = w.prerender;
exports.resumeAndPrerender = w.resumeAndPrerender;
-14
View File
@@ -37,17 +37,3 @@ export function resumeToPipeableStream() {
arguments,
);
}
export function renderToReadableStream() {
return require('./src/server/react-dom-server.node-webstreams').renderToReadableStream.apply(
this,
arguments,
);
}
export function resume() {
return require('./src/server/react-dom-server.node-webstreams').resume.apply(
this,
arguments,
);
}
@@ -1,43 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
* @jest-environment node
*/
'use strict';
let React;
let ReactDOMFizzServer;
describe('ReactDOMFizzServerNodeWebStreams', () => {
beforeEach(() => {
jest.resetModules();
jest.useRealTimers();
React = require('react');
ReactDOMFizzServer = require('react-dom/server.node');
});
async function readResult(stream) {
const reader = stream.getReader();
let result = '';
while (true) {
const {done, value} = await reader.read();
if (done) {
return result;
}
result += Buffer.from(value).toString('utf8');
}
}
it('should call renderToPipeableStream', async () => {
const stream = await ReactDOMFizzServer.renderToReadableStream(
<div>hello world</div>,
);
const result = await readResult(stream);
expect(result).toMatchInlineSnapshot(`"<div>hello world</div>"`);
});
});
@@ -1,177 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
* @jest-environment node
*/
'use strict';
import {
getVisibleChildren,
insertNodesAndExecuteScripts,
} from '../test-utils/FizzTestUtils';
let JSDOM;
let React;
let ReactDOMFizzServer;
let ReactDOMFizzStatic;
let Suspense;
let container;
let serverAct;
describe('ReactDOMFizzStaticNodeWebStreams', () => {
beforeEach(() => {
jest.resetModules();
serverAct = require('internal-test-utils').serverAct;
JSDOM = require('jsdom').JSDOM;
React = require('react');
ReactDOMFizzServer = require('react-dom/server.node');
ReactDOMFizzStatic = require('react-dom/static.node');
Suspense = React.Suspense;
const jsdom = new JSDOM(
// The Fizz runtime assumes requestAnimationFrame exists so we need to polyfill it.
'<script>window.requestAnimationFrame = setTimeout;</script>',
{
runScripts: 'dangerously',
},
);
global.window = jsdom.window;
global.document = jsdom.window.document;
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
document.body.removeChild(container);
});
async function readContent(stream) {
const reader = stream.getReader();
let content = '';
while (true) {
const {done, value} = await reader.read();
if (done) {
return content;
}
content += Buffer.from(value).toString('utf8');
}
}
async function readIntoContainer(stream) {
const reader = stream.getReader();
let result = '';
while (true) {
const {done, value} = await reader.read();
if (done) {
break;
}
result += Buffer.from(value).toString('utf8');
}
const temp = document.createElement('div');
temp.innerHTML = result;
await insertNodesAndExecuteScripts(temp, container, null);
jest.runAllTimers();
}
it('should call prerender', async () => {
const result = await serverAct(() =>
ReactDOMFizzStatic.prerender(<div>hello world</div>),
);
const prelude = await readContent(result.prelude);
expect(prelude).toMatchInlineSnapshot(`"<div>hello world</div>"`);
});
// @gate enableHalt
it('can resume render of a prerender', async () => {
const errors = [];
let resolveA;
const promiseA = new Promise(r => (resolveA = r));
let resolveB;
const promiseB = new Promise(r => (resolveB = r));
async function ComponentA() {
await promiseA;
return (
<Suspense fallback="Loading B">
<ComponentB />
</Suspense>
);
}
async function ComponentB() {
await promiseB;
return 'Hello';
}
function App() {
return (
<div>
<Suspense fallback="Loading A">
<ComponentA />
</Suspense>
</div>
);
}
const controller = new AbortController();
let pendingResult;
await serverAct(async () => {
pendingResult = ReactDOMFizzStatic.prerender(<App />, {
signal: controller.signal,
onError(x) {
errors.push(x.message);
},
});
});
controller.abort();
const prerendered = await pendingResult;
const postponedState = JSON.stringify(prerendered.postponed);
await readIntoContainer(prerendered.prelude);
expect(getVisibleChildren(container)).toEqual(<div>Loading A</div>);
await resolveA();
expect(prerendered.postponed).not.toBe(null);
const controller2 = new AbortController();
await serverAct(async () => {
pendingResult = ReactDOMFizzStatic.resumeAndPrerender(
<App />,
JSON.parse(postponedState),
{
signal: controller2.signal,
onError(x) {
errors.push(x.message);
},
},
);
});
controller2.abort();
const prerendered2 = await pendingResult;
const postponedState2 = JSON.stringify(prerendered2.postponed);
await readIntoContainer(prerendered2.prelude);
expect(getVisibleChildren(container)).toEqual(<div>Loading B</div>);
await resolveB();
const dynamic = await serverAct(() =>
ReactDOMFizzServer.resume(<App />, JSON.parse(postponedState2)),
);
await readIntoContainer(dynamic);
expect(getVisibleChildren(container)).toEqual(<div>Hello</div>);
});
});
@@ -1,11 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export * from './ReactDOMFizzServerEdge.js';
export {prerender, resumeAndPrerender} from './ReactDOMFizzStaticEdge.js';
@@ -1,11 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export {renderToReadableStream, version} from './ReactDOMFizzServerEdge.js';
export {prerender} from './ReactDOMFizzStaticEdge.js';
-14
View File
@@ -37,17 +37,3 @@ export function resumeAndPrerenderToNodeStream() {
arguments,
);
}
export function prerender() {
return require('./src/server/react-dom-server.node-webstreams').prerender.apply(
this,
arguments,
);
}
export function resumeAndPrerender() {
return require('./src/server/react-dom-server.node-webstreams').resumeAndPrerender.apply(
this,
arguments,
);
}
@@ -1,28 +1,7 @@
'use strict';
var n, w;
if (process.env.NODE_ENV === 'production') {
n = require('./cjs/react-server-dom-parcel-client.node.production.js');
w = require('./cjs/react-server-dom-parcel-client.node-webstreams.production.js');
module.exports = require('./cjs/react-server-dom-parcel-client.node.production.js');
} else {
n = require('./cjs/react-server-dom-parcel-client.node.development.js');
w = require('./cjs/react-server-dom-parcel-client.node-webstreams.development.js');
module.exports = require('./cjs/react-server-dom-parcel-client.node.development.js');
}
exports.registerServerReference = function (r, i, e) {
return w.registerServerReference(n.registerServerReference(r, i, e), i, e);
};
exports.createServerReference = function (i, c, e, d, f) {
return w.registerServerReference(
n.createServerReference(i, c, e, d, f),
i,
e
);
};
exports.createFromNodeStream = n.createFromNodeStream;
exports.createFromFetch = w.createFromFetch;
exports.createFromReadableStream = w.createFromReadableStream;
exports.createTemporaryReferenceSet = w.createTemporaryReferenceSet;
exports.encodeReply = w.encodeReply;
@@ -1,12 +1,10 @@
'use strict';
var s, w;
var s;
if (process.env.NODE_ENV === 'production') {
s = require('./cjs/react-server-dom-parcel-server.node.production.js');
w = require('./cjs/react-server-dom-parcel-server.node-webstreams.production.js');
} else {
s = require('./cjs/react-server-dom-parcel-server.node.development.js');
w = require('./cjs/react-server-dom-parcel-server.node-webstreams.development.js');
}
exports.renderToPipeableStream = s.renderToPipeableStream;
@@ -17,11 +15,5 @@ exports.decodeFormState = s.decodeFormState;
exports.createClientReference = s.createClientReference;
exports.registerServerReference = s.registerServerReference;
exports.createTemporaryReferenceSet = s.createTemporaryReferenceSet;
exports.registerServerActions = function (m) {
w.registerServerActions(m);
s.registerServerActions(m);
};
exports.registerServerActions = s.registerServerActions;
exports.loadServerAction = s.loadServerAction;
exports.renderToReadableStream = w.renderToReadableStream;
exports.decodeReplyFromAsyncIterable = w.decodeReplyFromAsyncIterable;
@@ -1,10 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export * from './ReactFlightDOMClientEdge';
@@ -1,22 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export {
renderToReadableStream,
prerender as unstable_prerender,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
createClientReference,
registerServerReference,
createTemporaryReferenceSet,
registerServerActions,
loadServerAction,
} from './ReactFlightDOMServerEdge';
@@ -1,28 +1,7 @@
'use strict';
var n, w;
if (process.env.NODE_ENV === 'production') {
n = require('./cjs/react-server-dom-turbopack-client.node.production.js');
w = require('./cjs/react-server-dom-turbopack-client.node-webstreams.production.js');
module.exports = require('./cjs/react-server-dom-turbopack-client.node.production.js');
} else {
n = require('./cjs/react-server-dom-turbopack-client.node.development.js');
w = require('./cjs/react-server-dom-turbopack-client.node-webstreams.development.js');
module.exports = require('./cjs/react-server-dom-turbopack-client.node.development.js');
}
exports.registerServerReference = function (r, i, e) {
return w.registerServerReference(n.registerServerReference(r, i, e), i, e);
};
exports.createServerReference = function (i, c, e, d, f) {
return w.registerServerReference(
n.createServerReference(i, c, e, d, f),
i,
e
);
};
exports.createFromNodeStream = n.createFromNodeStream;
exports.createFromFetch = w.createFromFetch;
exports.createFromReadableStream = w.createFromReadableStream;
exports.createTemporaryReferenceSet = w.createTemporaryReferenceSet;
exports.encodeReply = w.encodeReply;
@@ -1,12 +1,10 @@
'use strict';
var s, w;
var s;
if (process.env.NODE_ENV === 'production') {
s = require('./cjs/react-server-dom-turbopack-server.node.production.js');
w = require('./cjs/react-server-dom-turbopack-server.node-webstreams.production.js');
} else {
s = require('./cjs/react-server-dom-turbopack-server.node.development.js');
w = require('./cjs/react-server-dom-turbopack-server.node-webstreams.development.js');
}
exports.renderToPipeableStream = s.renderToPipeableStream;
@@ -18,6 +16,3 @@ exports.registerServerReference = s.registerServerReference;
exports.registerClientReference = s.registerClientReference;
exports.createClientModuleProxy = s.createClientModuleProxy;
exports.createTemporaryReferenceSet = s.createTemporaryReferenceSet;
exports.renderToReadableStream = w.renderToReadableStream;
exports.decodeReplyFromAsyncIterable = w.decodeReplyFromAsyncIterable;
@@ -1,10 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export * from './ReactFlightDOMClientEdge';
@@ -1,21 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export {
renderToReadableStream,
prerender as unstable_prerender,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
registerServerReference,
registerClientReference,
createClientModuleProxy,
createTemporaryReferenceSet,
} from './ReactFlightDOMServerEdge';
@@ -1,28 +1,7 @@
'use strict';
var n, w;
if (process.env.NODE_ENV === 'production') {
n = require('./cjs/react-server-dom-webpack-client.node.production.js');
w = require('./cjs/react-server-dom-webpack-client.node-webstreams.production.js');
module.exports = require('./cjs/react-server-dom-webpack-client.node.production.js');
} else {
n = require('./cjs/react-server-dom-webpack-client.node.development.js');
w = require('./cjs/react-server-dom-webpack-client.node-webstreams.development.js');
module.exports = require('./cjs/react-server-dom-webpack-client.node.development.js');
}
exports.registerServerReference = function (r, i, e) {
return w.registerServerReference(n.registerServerReference(r, i, e), i, e);
};
exports.createServerReference = function (i, c, e, d, f) {
return w.registerServerReference(
n.createServerReference(i, c, e, d, f),
i,
e
);
};
exports.createFromNodeStream = n.createFromNodeStream;
exports.createFromFetch = w.createFromFetch;
exports.createFromReadableStream = w.createFromReadableStream;
exports.createTemporaryReferenceSet = w.createTemporaryReferenceSet;
exports.encodeReply = w.encodeReply;
@@ -1,28 +1,7 @@
'use strict';
var n, w;
if (process.env.NODE_ENV === 'production') {
n = require('./cjs/react-server-dom-webpack-client.node.unbundled.production.js');
w = require('./cjs/react-server-dom-webpack-client.node-webstreams.unbundled.production.js');
module.exports = require('./cjs/react-server-dom-webpack-client.node.unbundled.production.js');
} else {
n = require('./cjs/react-server-dom-webpack-client.node.unbundled.development.js');
w = require('./cjs/react-server-dom-webpack-client.node-webstreams.unbundled.development.js');
module.exports = require('./cjs/react-server-dom-webpack-client.node.unbundled.development.js');
}
exports.registerServerReference = function (r, i, e) {
return w.registerServerReference(n.registerServerReference(r, i, e), i, e);
};
exports.createServerReference = function (i, c, e, d, f) {
return w.registerServerReference(
n.createServerReference(i, c, e, d, f),
i,
e
);
};
exports.createFromNodeStream = n.createFromNodeStream;
exports.createFromFetch = w.createFromFetch;
exports.createFromReadableStream = w.createFromReadableStream;
exports.createTemporaryReferenceSet = w.createTemporaryReferenceSet;
exports.encodeReply = w.encodeReply;
@@ -1,12 +1,10 @@
'use strict';
var s, w;
var s;
if (process.env.NODE_ENV === 'production') {
s = require('./cjs/react-server-dom-webpack-server.node.unbundled.production.js');
w = require('./cjs/react-server-dom-webpack-server.node-webstreams.unbundled.production.js');
s = require('./cjs/react-server-dom-webpack-server.node.production.js');
} else {
s = require('./cjs/react-server-dom-webpack-server.node.unbundled.development.js');
w = require('./cjs/react-server-dom-webpack-server.node-webstreams.unbundled.development.js');
s = require('./cjs/react-server-dom-webpack-server.node.development.js');
}
exports.renderToPipeableStream = s.renderToPipeableStream;
@@ -18,6 +16,3 @@ exports.registerServerReference = s.registerServerReference;
exports.registerClientReference = s.registerClientReference;
exports.createClientModuleProxy = s.createClientModuleProxy;
exports.createTemporaryReferenceSet = s.createTemporaryReferenceSet;
exports.renderToReadableStream = w.renderToReadableStream;
exports.decodeReplyFromAsyncIterable = w.decodeReplyFromAsyncIterable;
@@ -1,12 +1,10 @@
'use strict';
var s, w;
var s;
if (process.env.NODE_ENV === 'production') {
s = require('./cjs/react-server-dom-webpack-server.node.unbundled.production.js');
w = require('./cjs/react-server-dom-webpack-server.node-webstreams.unbundled.production.js');
} else {
s = require('./cjs/react-server-dom-webpack-server.node.unbundled.development.js');
w = require('./cjs/react-server-dom-webpack-server.node-webstreams.unbundled.development.js');
}
exports.renderToPipeableStream = s.renderToPipeableStream;
@@ -18,6 +16,3 @@ exports.registerServerReference = s.registerServerReference;
exports.registerClientReference = s.registerClientReference;
exports.createClientModuleProxy = s.createClientModuleProxy;
exports.createTemporaryReferenceSet = s.createTemporaryReferenceSet;
exports.renderToReadableStream = w.renderToReadableStream;
exports.decodeReplyFromAsyncIterable = w.decodeReplyFromAsyncIterable;
@@ -1,10 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export * from './ReactFlightDOMClientEdge';
@@ -1,10 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export * from './ReactFlightDOMClientEdge';
@@ -1,21 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export {
renderToReadableStream,
prerender as unstable_prerender,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
registerServerReference,
registerClientReference,
createClientModuleProxy,
createTemporaryReferenceSet,
} from './ReactFlightDOMServerEdge';
@@ -1,21 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export {
renderToReadableStream,
prerender as unstable_prerender,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
registerServerReference,
registerClientReference,
createClientModuleProxy,
createTemporaryReferenceSet,
} from './ReactFlightDOMServerEdge';
@@ -1,186 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import {TextEncoder} from 'util';
import {createHash} from 'crypto';
export type Destination = ReadableStreamController;
export type PrecomputedChunk = Uint8Array;
export opaque type Chunk = Uint8Array;
export type BinaryChunk = Uint8Array;
export function scheduleWork(callback: () => void) {
setImmediate(callback);
}
export const scheduleMicrotask = queueMicrotask;
export function flushBuffered(destination: Destination) {
// WHATWG Streams do not yet have a way to flush the underlying
// transform streams. https://github.com/whatwg/streams/issues/960
}
const VIEW_SIZE = 2048;
let currentView = null;
let writtenBytes = 0;
export function beginWriting(destination: Destination) {
currentView = new Uint8Array(VIEW_SIZE);
writtenBytes = 0;
}
export function writeChunk(
destination: Destination,
chunk: PrecomputedChunk | Chunk | BinaryChunk,
): void {
if (chunk.byteLength === 0) {
return;
}
if (chunk.byteLength > VIEW_SIZE) {
// this chunk may overflow a single view which implies it was not
// one that is cached by the streaming renderer. We will enqueu
// it directly and expect it is not re-used
if (writtenBytes > 0) {
destination.enqueue(
new Uint8Array(
((currentView: any): Uint8Array).buffer,
0,
writtenBytes,
),
);
currentView = new Uint8Array(VIEW_SIZE);
writtenBytes = 0;
}
destination.enqueue(chunk);
return;
}
let bytesToWrite = chunk;
const allowableBytes = ((currentView: any): Uint8Array).length - writtenBytes;
if (allowableBytes < bytesToWrite.byteLength) {
// this chunk would overflow the current view. We enqueue a full view
// and start a new view with the remaining chunk
if (allowableBytes === 0) {
// the current view is already full, send it
destination.enqueue(currentView);
} else {
// fill up the current view and apply the remaining chunk bytes
// to a new view.
((currentView: any): Uint8Array).set(
bytesToWrite.subarray(0, allowableBytes),
writtenBytes,
);
// writtenBytes += allowableBytes; // this can be skipped because we are going to immediately reset the view
destination.enqueue(currentView);
bytesToWrite = bytesToWrite.subarray(allowableBytes);
}
currentView = new Uint8Array(VIEW_SIZE);
writtenBytes = 0;
}
((currentView: any): Uint8Array).set(bytesToWrite, writtenBytes);
writtenBytes += bytesToWrite.byteLength;
}
export function writeChunkAndReturn(
destination: Destination,
chunk: PrecomputedChunk | Chunk | BinaryChunk,
): boolean {
writeChunk(destination, chunk);
// in web streams there is no backpressure so we can alwas write more
return true;
}
export function completeWriting(destination: Destination) {
if (currentView && writtenBytes > 0) {
destination.enqueue(new Uint8Array(currentView.buffer, 0, writtenBytes));
currentView = null;
writtenBytes = 0;
}
}
export function close(destination: Destination) {
destination.close();
}
const textEncoder = new TextEncoder();
export function stringToChunk(content: string): Chunk {
return textEncoder.encode(content);
}
export function stringToPrecomputedChunk(content: string): PrecomputedChunk {
const precomputedChunk = textEncoder.encode(content);
if (__DEV__) {
if (precomputedChunk.byteLength > VIEW_SIZE) {
console.error(
'precomputed chunks must be smaller than the view size configured for this host. This is a bug in React.',
);
}
}
return precomputedChunk;
}
export function typedArrayToBinaryChunk(
content: $ArrayBufferView,
): BinaryChunk {
// Convert any non-Uint8Array array to Uint8Array. We could avoid this for Uint8Arrays.
// If we passed through this straight to enqueue we wouldn't have to convert it but since
// we need to copy the buffer in that case, we need to convert it to copy it.
// When we copy it into another array using set() it needs to be a Uint8Array.
const buffer = new Uint8Array(
content.buffer,
content.byteOffset,
content.byteLength,
);
// We clone large chunks so that we can transfer them when we write them.
// Others get copied into the target buffer.
return content.byteLength > VIEW_SIZE ? buffer.slice() : buffer;
}
export function byteLengthOfChunk(chunk: Chunk | PrecomputedChunk): number {
return chunk.byteLength;
}
export function byteLengthOfBinaryChunk(chunk: BinaryChunk): number {
return chunk.byteLength;
}
export function closeWithError(destination: Destination, error: mixed): void {
// $FlowFixMe[method-unbinding]
if (typeof destination.error === 'function') {
// $FlowFixMe[incompatible-call]: This is an Error object or the destination accepts other types.
destination.error(error);
} else {
// Earlier implementations doesn't support this method. In that environment you're
// supposed to throw from a promise returned but we don't return a promise in our
// approach. We could fork this implementation but this is environment is an edge
// case to begin with. It's even less common to run this in an older environment.
// Even then, this is not where errors are supposed to happen and they get reported
// to a global callback in addition to this anyway. So it's fine just to close this.
destination.close();
}
}
export function createFastHash(input: string): string | number {
const hash = createHash('md5');
hash.update(input);
return hash.digest('hex');
}
export function readAsDataURL(blob: Blob): Promise<string> {
return blob.arrayBuffer().then(arrayBuffer => {
const encoded = Buffer.from(arrayBuffer).toString('base64');
const mimeType = blob.type || 'application/octet-stream';
return 'data:' + mimeType + ';base64,' + encoded;
});
}
@@ -1,10 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export * from '../ReactServerStreamConfigNodeWebStreams';
+2 -7
View File
@@ -296,19 +296,14 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
// We mock createHook so that we can automatically clean it up.
let installedHook = null;
let outgoingHook = null;
jest.mock('async_hooks', () => {
const actual = jest.requireActual('async_hooks');
return {
...actual,
createHook(config) {
// We unmount when there's more than two hooks installed.
// We use two because the build of server.node actually installs two hooks.
// One in each build.
if (outgoingHook) {
outgoingHook.disable();
if (installedHook) {
installedHook.disable();
}
outgoingHook = installedHook;
return (installedHook = actual.createHook(config));
},
};
-91
View File
@@ -365,16 +365,6 @@ const bundles = [
wrapWithModuleBoundaries: false,
externals: ['react', 'util', 'crypto', 'async_hooks', 'react-dom'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
entry: 'react-dom/src/server/react-dom-server.node-webstreams.js',
name: 'react-dom-server.node-webstreams',
global: 'ReactDOMServer',
minifyWithProdErrorCodes: false,
wrapWithModuleBoundaries: false,
externals: ['react', 'util', 'crypto', 'async_hooks', 'react-dom'],
},
{
bundleTypes: __EXPERIMENTAL__ ? [FB_WWW_DEV, FB_WWW_PROD] : [],
moduleType: RENDERER,
@@ -472,18 +462,6 @@ const bundles = [
wrapWithModuleBoundaries: false,
externals: ['react', 'util', 'crypto', 'async_hooks', 'react-dom'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
entry:
'react-server-dom-webpack/src/server/react-flight-dom-server.node-webstreams',
name: 'react-server-dom-webpack-server.node-webstreams',
condition: 'react-server',
global: 'ReactServerDOMServer',
minifyWithProdErrorCodes: false,
wrapWithModuleBoundaries: false,
externals: ['react', 'util', 'crypto', 'async_hooks', 'react-dom'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
@@ -496,18 +474,6 @@ const bundles = [
wrapWithModuleBoundaries: false,
externals: ['react', 'util', 'crypto', 'async_hooks', 'react-dom'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
entry:
'react-server-dom-webpack/src/server/react-flight-dom-server.node-webstreams.unbundled',
name: 'react-server-dom-webpack-server.node-webstreams.unbundled',
condition: 'react-server',
global: 'ReactServerDOMServer',
minifyWithProdErrorCodes: false,
wrapWithModuleBoundaries: false,
externals: ['react', 'util', 'crypto', 'async_hooks', 'react-dom'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
@@ -542,17 +508,6 @@ const bundles = [
wrapWithModuleBoundaries: false,
externals: ['react', 'react-dom', 'util', 'crypto'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
entry:
'react-server-dom-webpack/src/client/react-flight-dom-client.node-webstreams',
name: 'react-server-dom-webpack-client.node-webstreams',
global: 'ReactServerDOMClient',
minifyWithProdErrorCodes: false,
wrapWithModuleBoundaries: false,
externals: ['react', 'react-dom', 'util', 'crypto'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
@@ -564,17 +519,6 @@ const bundles = [
wrapWithModuleBoundaries: false,
externals: ['react', 'react-dom', 'util', 'crypto'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
entry:
'react-server-dom-webpack/src/client/react-flight-dom-client.node-webstreams.unbundled',
name: 'react-server-dom-webpack-client.node-webstreams.unbundled',
global: 'ReactServerDOMClient',
minifyWithProdErrorCodes: false,
wrapWithModuleBoundaries: false,
externals: ['react', 'react-dom', 'util', 'crypto'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
@@ -646,18 +590,6 @@ const bundles = [
wrapWithModuleBoundaries: false,
externals: ['react', 'util', 'async_hooks', 'react-dom'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
entry:
'react-server-dom-turbopack/src/server/react-flight-dom-server.node-webstreams',
name: 'react-server-dom-turbopack-server.node-webstreams',
condition: 'react-server',
global: 'ReactServerDOMServer',
minifyWithProdErrorCodes: false,
wrapWithModuleBoundaries: false,
externals: ['react', 'util', 'async_hooks', 'react-dom'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
@@ -692,17 +624,6 @@ const bundles = [
wrapWithModuleBoundaries: false,
externals: ['react', 'react-dom', 'util'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
entry:
'react-server-dom-turbopack/src/client/react-flight-dom-client.node-webstreams',
name: 'react-server-dom-turbopack-client.node-webstreams',
global: 'ReactServerDOMClient',
minifyWithProdErrorCodes: false,
wrapWithModuleBoundaries: false,
externals: ['react', 'react-dom', 'util'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
@@ -737,18 +658,6 @@ const bundles = [
wrapWithModuleBoundaries: false,
externals: ['react', 'util', 'async_hooks', 'react-dom'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
entry:
'react-server-dom-parcel/src/server/react-flight-dom-server.node-webstreams',
name: 'react-server-dom-parcel-server.node-webstreams',
condition: 'react-server',
global: 'ReactServerDOMServer',
minifyWithProdErrorCodes: false,
wrapWithModuleBoundaries: false,
externals: ['react', 'util', 'async_hooks', 'react-dom'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
-80
View File
@@ -104,47 +104,6 @@ module.exports = [
isFlowTyped: true,
isServerSupported: true,
},
{
shortName: 'dom-node-webstreams',
entryPoints: [
'react-dom/src/server/react-dom-server.node-webstreams.js',
'react-server-dom-webpack/src/client/react-flight-dom-client.node-webstreams.unbundled',
'react-server-dom-webpack/src/server/react-flight-dom-server.node-webstreams.unbundled',
],
paths: [
'react-dom',
'react-dom/src/ReactDOMReactServer.js',
'react-dom-bindings',
'react-dom/client',
'react-dom/profiling',
'react-dom/server',
'react-dom/server.node',
'react-dom/static',
'react-dom/static.node',
'react-dom/test-utils',
'react-dom/src/server/react-dom-server.node-webstreams',
'react-dom/src/server/ReactDOMFizzServerEdge.js',
'react-dom/src/server/ReactDOMFizzStaticEdge.js',
'react-dom-bindings/src/server/ReactDOMFlightServerHostDispatcher.js',
'react-dom-bindings/src/server/ReactFlightServerConfigDOM.js',
'react-dom-bindings/src/shared/ReactFlightClientConfigDOM.js',
'react-server-dom-webpack',
'react-server-dom-webpack/client.node.unbundled',
'react-server-dom-webpack/server',
'react-server-dom-webpack/server.node.unbundled',
'react-server-dom-webpack/static',
'react-server-dom-webpack/static.node.unbundled',
'react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js', // react-server-dom-webpack/client.node
'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerNode.js',
'react-server-dom-webpack/src/client/react-flight-dom-client.node-webstreams.unbundled',
'react-server-dom-webpack/src/server/react-flight-dom-server.node-webstreams.unbundled',
'react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js', // react-server-dom-webpack/src/server/react-flight-dom-server.node
'shared/ReactDOMSharedInternals',
'react-server/src/ReactFlightServerConfigDebugNode.js',
],
isFlowTyped: true,
isServerSupported: true,
},
{
shortName: 'dom-node-webpack',
entryPoints: [
@@ -190,19 +149,6 @@ module.exports = [
isFlowTyped: true,
isServerSupported: true,
},
{
shortName: 'dom-node-webstreams-webpack',
entryPoints: [
'react-server-dom-webpack/src/client/react-flight-dom-client.node-webstreams',
'react-server-dom-webpack/src/server/react-flight-dom-server.node-webstreams',
],
paths: [
'react-server-dom-webpack/src/client/react-flight-dom-client.node-webstreams',
'react-server-dom-webpack/src/server/react-flight-dom-server.node-webstreams',
],
isFlowTyped: false,
isServerSupported: true,
},
{
shortName: 'dom-node-turbopack',
entryPoints: [
@@ -248,19 +194,6 @@ module.exports = [
isFlowTyped: true,
isServerSupported: true,
},
{
shortName: 'dom-node-webstreams-turbopack',
entryPoints: [
'react-server-dom-turbopack/src/client/react-flight-dom-client.node-webstreams',
'react-server-dom-turbopack/src/server/react-flight-dom-server.node-webstreams',
],
paths: [
'react-server-dom-turbopack/src/client/react-flight-dom-client.node-webstreams',
'react-server-dom-turbopack/src/server/react-flight-dom-server.node-webstreams',
],
isFlowTyped: false,
isServerSupported: true,
},
{
shortName: 'dom-node-parcel',
entryPoints: [
@@ -303,19 +236,6 @@ module.exports = [
isFlowTyped: true,
isServerSupported: true,
},
{
shortName: 'dom-node-webstreams-parcel',
entryPoints: [
'react-server-dom-parcel/src/client/react-flight-dom-client.node-webstreams',
'react-server-dom-parcel/src/server/react-flight-dom-server.node-webstreams',
],
paths: [
'react-server-dom-parcel/src/client/react-flight-dom-client.node-webstreams',
'react-server-dom-parcel/src/server/react-flight-dom-server.node-webstreams',
],
isFlowTyped: false,
isServerSupported: true,
},
{
shortName: 'dom-bun',
entryPoints: ['react-dom/src/server/react-dom-server.bun.js'],