From e8d15fa19efcd18f0947fe4189652f5b64f74256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Fri, 6 Jun 2025 11:07:15 -0400 Subject: [PATCH] [Flight] Build node-webstreams version of bundled webpack server (#33456) Follow up to #33442. This is the bundled version. To keep type check passes from exploding and the maintainance of the annoying `paths: []` list small, this doesn't add this to flow type checks. We might miss some config but every combination should already be covered by other one passes. I also don't add any jest tests because to test these double export entry points we need conditional importing to cover builds and non-builds which turns out to be difficult for the Flight builds so these aren't covered by any basic build tests. This approach is what I'm going for, for the other bundlers too. --- ...lientConfig.dom-node-webstreams-webpack.js | 19 ++++++++++++++ .../npm/client.node.js | 25 +++++++++++++++++-- .../npm/server.node.js | 11 +++++--- ...react-flight-dom-client.node-webstreams.js | 10 ++++++++ ...react-flight-dom-server.node-webstreams.js | 21 ++++++++++++++++ scripts/jest/setupTests.js | 9 +++++-- scripts/rollup/bundles.js | 23 +++++++++++++++++ scripts/shared/inlinedHostConfigs.js | 13 ++++++++++ 8 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 packages/react-client/src/forks/ReactFlightClientConfig.dom-node-webstreams-webpack.js create mode 100644 packages/react-server-dom-webpack/src/client/react-flight-dom-client.node-webstreams.js create mode 100644 packages/react-server-dom-webpack/src/server/react-flight-dom-server.node-webstreams.js diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-webstreams-webpack.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-webstreams-webpack.js new file mode 100644 index 0000000000..f328a3e2ed --- /dev/null +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-webstreams-webpack.js @@ -0,0 +1,19 @@ +/** + * 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; diff --git a/packages/react-server-dom-webpack/npm/client.node.js b/packages/react-server-dom-webpack/npm/client.node.js index 32b45503d1..71a093f0cd 100644 --- a/packages/react-server-dom-webpack/npm/client.node.js +++ b/packages/react-server-dom-webpack/npm/client.node.js @@ -1,7 +1,28 @@ 'use strict'; +var n, w; if (process.env.NODE_ENV === 'production') { - module.exports = require('./cjs/react-server-dom-webpack-client.node.production.js'); + n = require('./cjs/react-server-dom-webpack-client.node.production.js'); + w = require('./cjs/react-server-dom-webpack-client.node-webstreams.production.js'); } else { - module.exports = require('./cjs/react-server-dom-webpack-client.node.development.js'); + n = require('./cjs/react-server-dom-webpack-client.node.development.js'); + w = require('./cjs/react-server-dom-webpack-client.node-webstreams.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; diff --git a/packages/react-server-dom-webpack/npm/server.node.js b/packages/react-server-dom-webpack/npm/server.node.js index 6885e43a44..2d215c45d5 100644 --- a/packages/react-server-dom-webpack/npm/server.node.js +++ b/packages/react-server-dom-webpack/npm/server.node.js @@ -1,10 +1,12 @@ 'use strict'; -var s; +var s, w; if (process.env.NODE_ENV === 'production') { - s = require('./cjs/react-server-dom-webpack-server.node.production.js'); + 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.development.js'); + 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; @@ -16,3 +18,6 @@ exports.registerServerReference = s.registerServerReference; exports.registerClientReference = s.registerClientReference; exports.createClientModuleProxy = s.createClientModuleProxy; exports.createTemporaryReferenceSet = s.createTemporaryReferenceSet; + +exports.renderToReadableStream = w.renderToReadableStream; +exports.decodeReplyFromAsyncIterable = w.decodeReplyFromAsyncIterable; diff --git a/packages/react-server-dom-webpack/src/client/react-flight-dom-client.node-webstreams.js b/packages/react-server-dom-webpack/src/client/react-flight-dom-client.node-webstreams.js new file mode 100644 index 0000000000..14a8876953 --- /dev/null +++ b/packages/react-server-dom-webpack/src/client/react-flight-dom-client.node-webstreams.js @@ -0,0 +1,10 @@ +/** + * 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'; diff --git a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node-webstreams.js b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node-webstreams.js new file mode 100644 index 0000000000..9198f9913e --- /dev/null +++ b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node-webstreams.js @@ -0,0 +1,21 @@ +/** + * 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'; diff --git a/scripts/jest/setupTests.js b/scripts/jest/setupTests.js index 1e8d8e5276..175e0cd7ca 100644 --- a/scripts/jest/setupTests.js +++ b/scripts/jest/setupTests.js @@ -296,14 +296,19 @@ 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) { - if (installedHook) { - installedHook.disable(); + // 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(); } + outgoingHook = installedHook; return (installedHook = actual.createHook(config)); }, }; diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 6bb622c62b..78f633009b 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -472,6 +472,18 @@ 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, @@ -530,6 +542,17 @@ 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, diff --git a/scripts/shared/inlinedHostConfigs.js b/scripts/shared/inlinedHostConfigs.js index 24db4fe0ea..d169e1fcde 100644 --- a/scripts/shared/inlinedHostConfigs.js +++ b/scripts/shared/inlinedHostConfigs.js @@ -190,6 +190,19 @@ 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: [