From 7cb356e8622e6413671bc22ea273ea39b0b265e4 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Tue, 10 Dec 2024 11:51:39 -0800 Subject: [PATCH 1/3] [Flight] rename `prerender` to `unstable_prerender` and include in stable channel (#31724) We added an experimental `prerender` API to flight. This change exposes this API in stable channels prefixed as `unstable_prerender`. We have high confidence this API should exist but because we have not yet settled on how to handle resuming/replaying of RSC streams we may need to change the API contract to suit future needs. This release will allow us to get more usage out of the existing implemented functionality without requiring you to use experimental builds which will open up greater adoption and opportunity for feedback. the `prerender` implementation is documented in the `react-server` package. As with all RSC APIs implemented in bundler specific binding packages these aren't intended to be called by end users but instead be used by frameworks implementing React Server Components. Previously `prerender` was exposed unprefixed and only in the experimental channel. This PR renames the export across all channels to `unstable_prerender` so users of this previously unprefixed api will need to update to the unstable form. This isn't a breaking change because it was only exposed in the experimental channel which does not follow semver. The reason we don't expose it under both names is that users may feature detect the unprefixed form and then when we finally do ship it as unprefixed we may change the function signature and break this code. Changing the name now is much safer. --- fixtures/flight/server/region.js | 2 +- .../react-server-dom-esm/npm/static.node.js | 4 +- .../server/react-flight-dom-server.node.js | 2 +- .../react-flight-dom-server.node.stable.js | 1 + packages/react-server-dom-esm/static.node.js | 2 +- .../npm/static.browser.js | 4 +- .../npm/static.edge.js | 4 +- .../npm/static.node.js | 4 +- .../server/react-flight-dom-server.browser.js | 2 +- .../react-flight-dom-server.browser.stable.js | 1 + .../server/react-flight-dom-server.edge.js | 2 +- .../react-flight-dom-server.edge.stable.js | 1 + .../server/react-flight-dom-server.node.js | 2 +- .../react-flight-dom-server.node.stable.js | 1 + .../static.browser.js | 2 +- .../react-server-dom-turbopack/static.edge.js | 2 +- .../react-server-dom-turbopack/static.node.js | 2 +- .../npm/static.browser.js | 4 +- .../npm/static.edge.js | 4 +- .../npm/static.node.js | 4 +- .../npm/static.node.unbundled.js | 4 +- .../src/__tests__/ReactFlightDOM-test.js | 70 ++++++++++--------- .../__tests__/ReactFlightDOMBrowser-test.js | 4 +- .../src/__tests__/ReactFlightDOMEdge-test.js | 4 +- .../src/__tests__/ReactFlightDOMNode-test.js | 28 ++++---- .../server/react-flight-dom-server.browser.js | 2 +- .../react-flight-dom-server.browser.stable.js | 1 + .../server/react-flight-dom-server.edge.js | 2 +- .../react-flight-dom-server.edge.stable.js | 1 + .../server/react-flight-dom-server.node.js | 2 +- .../react-flight-dom-server.node.stable.js | 1 + .../react-flight-dom-server.node.unbundled.js | 2 +- ...flight-dom-server.node.unbundled.stable.js | 1 + .../static.browser.js | 2 +- .../react-server-dom-webpack/static.edge.js | 2 +- .../react-server-dom-webpack/static.node.js | 2 +- .../static.node.unbundled.js | 2 +- 37 files changed, 97 insertions(+), 83 deletions(-) diff --git a/fixtures/flight/server/region.js b/fixtures/flight/server/region.js index daf619741a1ea..6896713e41cbf 100644 --- a/fixtures/flight/server/region.js +++ b/fixtures/flight/server/region.js @@ -106,7 +106,7 @@ async function renderApp(res, returnValue, formState) { } async function prerenderApp(res, returnValue, formState) { - const {prerenderToNodeStream} = await import( + const {unstable_prerenderToNodeStream: prerenderToNodeStream} = await import( 'react-server-dom-webpack/static' ); // const m = require('../src/App.js'); diff --git a/packages/react-server-dom-esm/npm/static.node.js b/packages/react-server-dom-esm/npm/static.node.js index ff0b9b2a42f2f..7fb451a3cd807 100644 --- a/packages/react-server-dom-esm/npm/static.node.js +++ b/packages/react-server-dom-esm/npm/static.node.js @@ -7,6 +7,6 @@ if (process.env.NODE_ENV === 'production') { s = require('./cjs/react-server-dom-esm-server.node.development.js'); } -if (s.prerenderToNodeStream) { - exports.prerenderToNodeStream = s.prerenderToNodeStream; +if (s.unstable_prerenderToNodeStream) { + exports.unstable_prerenderToNodeStream = s.unstable_prerenderToNodeStream; } diff --git a/packages/react-server-dom-esm/src/server/react-flight-dom-server.node.js b/packages/react-server-dom-esm/src/server/react-flight-dom-server.node.js index f24946fcae8bb..7d5b19a521ea7 100644 --- a/packages/react-server-dom-esm/src/server/react-flight-dom-server.node.js +++ b/packages/react-server-dom-esm/src/server/react-flight-dom-server.node.js @@ -9,7 +9,7 @@ export { renderToPipeableStream, - prerenderToNodeStream, + prerenderToNodeStream as unstable_prerenderToNodeStream, decodeReplyFromBusboy, decodeReply, decodeAction, diff --git a/packages/react-server-dom-esm/src/server/react-flight-dom-server.node.stable.js b/packages/react-server-dom-esm/src/server/react-flight-dom-server.node.stable.js index d14d2b8ed362a..7d5b19a521ea7 100644 --- a/packages/react-server-dom-esm/src/server/react-flight-dom-server.node.stable.js +++ b/packages/react-server-dom-esm/src/server/react-flight-dom-server.node.stable.js @@ -9,6 +9,7 @@ export { renderToPipeableStream, + prerenderToNodeStream as unstable_prerenderToNodeStream, decodeReplyFromBusboy, decodeReply, decodeAction, diff --git a/packages/react-server-dom-esm/static.node.js b/packages/react-server-dom-esm/static.node.js index d15eddc6f9b0e..345f4123c9f09 100644 --- a/packages/react-server-dom-esm/static.node.js +++ b/packages/react-server-dom-esm/static.node.js @@ -7,4 +7,4 @@ * @flow */ -export {prerenderToNodeStream} from './src/server/react-flight-dom-server.node'; +export {unstable_prerenderToNodeStream} from './src/server/react-flight-dom-server.node'; diff --git a/packages/react-server-dom-turbopack/npm/static.browser.js b/packages/react-server-dom-turbopack/npm/static.browser.js index edc104a459383..d04d771c2d3b6 100644 --- a/packages/react-server-dom-turbopack/npm/static.browser.js +++ b/packages/react-server-dom-turbopack/npm/static.browser.js @@ -7,6 +7,6 @@ if (process.env.NODE_ENV === 'production') { s = require('./cjs/react-server-dom-turbopack-server.browser.development.js'); } -if (s.prerender) { - exports.prerender = s.prerender; +if (s.unstable_prerender) { + exports.unstable_prerender = s.unstable_prerender; } diff --git a/packages/react-server-dom-turbopack/npm/static.edge.js b/packages/react-server-dom-turbopack/npm/static.edge.js index c074f8ffe7ee4..6d9ca4b3e8b84 100644 --- a/packages/react-server-dom-turbopack/npm/static.edge.js +++ b/packages/react-server-dom-turbopack/npm/static.edge.js @@ -7,6 +7,6 @@ if (process.env.NODE_ENV === 'production') { s = require('./cjs/react-server-dom-turbopack-server.edge.development.js'); } -if (s.prerender) { - exports.prerender = s.prerender; +if (s.unstable_prerender) { + exports.unstable_prerender = s.unstable_prerender; } diff --git a/packages/react-server-dom-turbopack/npm/static.node.js b/packages/react-server-dom-turbopack/npm/static.node.js index 84083a965189b..544a15530d24f 100644 --- a/packages/react-server-dom-turbopack/npm/static.node.js +++ b/packages/react-server-dom-turbopack/npm/static.node.js @@ -7,6 +7,6 @@ if (process.env.NODE_ENV === 'production') { s = require('./cjs/react-server-dom-turbopack-server.node.development.js'); } -if (s.prerenderToNodeStream) { - exports.prerenderToNodeStream = s.prerenderToNodeStream; +if (s.unstable_prerenderToNodeStream) { + exports.unstable_prerenderToNodeStream = s.unstable_prerenderToNodeStream; } diff --git a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.browser.js b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.browser.js index d8373ec551bc0..c0860225d7b57 100644 --- a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.browser.js +++ b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.browser.js @@ -9,7 +9,7 @@ export { renderToReadableStream, - prerender, + prerender as unstable_prerender, decodeReply, decodeAction, decodeFormState, diff --git a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.browser.stable.js b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.browser.stable.js index 0100b65554aec..c0860225d7b57 100644 --- a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.browser.stable.js +++ b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.browser.stable.js @@ -9,6 +9,7 @@ export { renderToReadableStream, + prerender as unstable_prerender, decodeReply, decodeAction, decodeFormState, diff --git a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.edge.js b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.edge.js index 9521ba6b68841..48c4fc4553e6b 100644 --- a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.edge.js +++ b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.edge.js @@ -9,7 +9,7 @@ export { renderToReadableStream, - prerender, + prerender as unstable_prerender, decodeReply, decodeAction, decodeFormState, diff --git a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.edge.stable.js b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.edge.stable.js index eb887b73a8ae8..48c4fc4553e6b 100644 --- a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.edge.stable.js +++ b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.edge.stable.js @@ -9,6 +9,7 @@ export { renderToReadableStream, + prerender as unstable_prerender, decodeReply, decodeAction, decodeFormState, diff --git a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.js b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.js index badc2ed50b691..fde57467327b6 100644 --- a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.js +++ b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.js @@ -9,7 +9,7 @@ export { renderToPipeableStream, - prerenderToNodeStream, + prerenderToNodeStream as unstable_prerenderToNodeStream, decodeReplyFromBusboy, decodeReply, decodeAction, diff --git a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.stable.js b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.stable.js index 0d159704067ea..fde57467327b6 100644 --- a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.stable.js +++ b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.stable.js @@ -9,6 +9,7 @@ export { renderToPipeableStream, + prerenderToNodeStream as unstable_prerenderToNodeStream, decodeReplyFromBusboy, decodeReply, decodeAction, diff --git a/packages/react-server-dom-turbopack/static.browser.js b/packages/react-server-dom-turbopack/static.browser.js index 2589789163206..3281fed6ea29c 100644 --- a/packages/react-server-dom-turbopack/static.browser.js +++ b/packages/react-server-dom-turbopack/static.browser.js @@ -7,4 +7,4 @@ * @flow */ -export {prerender} from './src/server/react-flight-dom-server.browser'; +export {unstable_prerender} from './src/server/react-flight-dom-server.browser'; diff --git a/packages/react-server-dom-turbopack/static.edge.js b/packages/react-server-dom-turbopack/static.edge.js index a39d54c73f579..b1a96317ae9b3 100644 --- a/packages/react-server-dom-turbopack/static.edge.js +++ b/packages/react-server-dom-turbopack/static.edge.js @@ -7,4 +7,4 @@ * @flow */ -export {prerender} from './src/server/react-flight-dom-server.edge'; +export {unstable_prerender} from './src/server/react-flight-dom-server.edge'; diff --git a/packages/react-server-dom-turbopack/static.node.js b/packages/react-server-dom-turbopack/static.node.js index d15eddc6f9b0e..345f4123c9f09 100644 --- a/packages/react-server-dom-turbopack/static.node.js +++ b/packages/react-server-dom-turbopack/static.node.js @@ -7,4 +7,4 @@ * @flow */ -export {prerenderToNodeStream} from './src/server/react-flight-dom-server.node'; +export {unstable_prerenderToNodeStream} from './src/server/react-flight-dom-server.node'; diff --git a/packages/react-server-dom-webpack/npm/static.browser.js b/packages/react-server-dom-webpack/npm/static.browser.js index 7d514abd6bf71..8c8951a62b9ea 100644 --- a/packages/react-server-dom-webpack/npm/static.browser.js +++ b/packages/react-server-dom-webpack/npm/static.browser.js @@ -7,6 +7,6 @@ if (process.env.NODE_ENV === 'production') { s = require('./cjs/react-server-dom-webpack-server.browser.development.js'); } -if (s.prerender) { - exports.prerender = s.prerender; +if (s.unstable_prerender) { + exports.unstable_prerender = s.unstable_prerender; } diff --git a/packages/react-server-dom-webpack/npm/static.edge.js b/packages/react-server-dom-webpack/npm/static.edge.js index a4ae48f55eb1b..975a4b5b87281 100644 --- a/packages/react-server-dom-webpack/npm/static.edge.js +++ b/packages/react-server-dom-webpack/npm/static.edge.js @@ -7,6 +7,6 @@ if (process.env.NODE_ENV === 'production') { s = require('./cjs/react-server-dom-webpack-server.edge.development.js'); } -if (s.prerender) { - exports.prerender = s.prerender; +if (s.unstable_prerender) { + exports.unstable_prerender = s.unstable_prerender; } diff --git a/packages/react-server-dom-webpack/npm/static.node.js b/packages/react-server-dom-webpack/npm/static.node.js index dbc4179d3e788..6346a449d3b48 100644 --- a/packages/react-server-dom-webpack/npm/static.node.js +++ b/packages/react-server-dom-webpack/npm/static.node.js @@ -7,6 +7,6 @@ if (process.env.NODE_ENV === 'production') { s = require('./cjs/react-server-dom-webpack-server.node.development.js'); } -if (s.prerenderToNodeStream) { - exports.prerenderToNodeStream = s.prerenderToNodeStream; +if (s.unstable_prerenderToNodeStream) { + exports.unstable_prerenderToNodeStream = s.unstable_prerenderToNodeStream; } diff --git a/packages/react-server-dom-webpack/npm/static.node.unbundled.js b/packages/react-server-dom-webpack/npm/static.node.unbundled.js index 73c8a3b86e9c7..5df3d5bf7afbc 100644 --- a/packages/react-server-dom-webpack/npm/static.node.unbundled.js +++ b/packages/react-server-dom-webpack/npm/static.node.unbundled.js @@ -7,6 +7,6 @@ if (process.env.NODE_ENV === 'production') { s = require('./cjs/react-server-dom-webpack-server.node.unbundled.development.js'); } -if (s.prerenderToNodeStream) { - exports.prerenderToNodeStream = s.prerenderToNodeStream; +if (s.unstable_prerenderToNodeStream) { + exports.unstable_prerenderToNodeStream = s.unstable_prerenderToNodeStream; } 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 d81a4c2f0149d..1cd688632c41e 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js @@ -2787,10 +2787,11 @@ describe('ReactFlightDOM', () => { const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { - pendingResult: ReactServerDOMStaticServer.prerenderToNodeStream( - , - webpackMap, - ), + pendingResult: + ReactServerDOMStaticServer.unstable_prerenderToNodeStream( + , + webpackMap, + ), }; }); @@ -2853,16 +2854,17 @@ describe('ReactFlightDOM', () => { const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { - pendingResult: ReactServerDOMStaticServer.prerenderToNodeStream( - , - webpackMap, - { - signal: controller.signal, - onError(err) { - errors.push(err); + pendingResult: + ReactServerDOMStaticServer.unstable_prerenderToNodeStream( + , + webpackMap, + { + signal: controller.signal, + onError(err) { + errors.push(err); + }, }, - }, - ), + ), }; }); @@ -2934,18 +2936,19 @@ describe('ReactFlightDOM', () => { const controller = new AbortController(); const {pendingResult} = await serverAct(() => { return { - pendingResult: ReactServerDOMStaticServer.prerenderToNodeStream( - { - multiShotIterable, - }, - {}, - { - onError(x) { - errors.push(x); + pendingResult: + ReactServerDOMStaticServer.unstable_prerenderToNodeStream( + { + multiShotIterable, }, - signal: controller.signal, - }, - ), + {}, + { + onError(x) { + errors.push(x); + }, + signal: controller.signal, + }, + ), }; }); @@ -3017,16 +3020,17 @@ describe('ReactFlightDOM', () => { const errors = []; const {pendingResult} = await serverAct(() => { return { - pendingResult: ReactServerDOMStaticServer.prerenderToNodeStream( - , - {}, - { - onError(x) { - errors.push(x); + pendingResult: + ReactServerDOMStaticServer.unstable_prerenderToNodeStream( + , + {}, + { + onError(x) { + errors.push(x); + }, + signal: controller.signal, }, - signal: controller.signal, - }, - ), + ), }; }); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js index 6803dfcfe2226..718c1c3a20264 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -2490,7 +2490,7 @@ describe('ReactFlightDOMBrowser', () => { const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { - pendingResult: ReactServerDOMStaticServer.prerender( + pendingResult: ReactServerDOMStaticServer.unstable_prerender( , webpackMap, ), @@ -2543,7 +2543,7 @@ describe('ReactFlightDOMBrowser', () => { const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { - pendingResult: ReactServerDOMStaticServer.prerender( + pendingResult: ReactServerDOMStaticServer.unstable_prerender( , webpackMap, { diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index ad936391b7f4e..947133149aef7 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -1134,7 +1134,7 @@ describe('ReactFlightDOMEdge', () => { const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { - pendingResult: ReactServerDOMStaticServer.prerender( + pendingResult: ReactServerDOMStaticServer.unstable_prerender( , webpackMap, ), @@ -1192,7 +1192,7 @@ describe('ReactFlightDOMEdge', () => { const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { - pendingResult: ReactServerDOMStaticServer.prerender( + pendingResult: ReactServerDOMStaticServer.unstable_prerender( , webpackMap, { diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js index d7e947345546f..ada19fb1fc44b 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js @@ -411,10 +411,11 @@ describe('ReactFlightDOMNode', () => { const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { - pendingResult: ReactServerDOMStaticServer.prerenderToNodeStream( - , - webpackMap, - ), + pendingResult: + ReactServerDOMStaticServer.unstable_prerenderToNodeStream( + , + webpackMap, + ), }; }); @@ -469,16 +470,17 @@ describe('ReactFlightDOMNode', () => { const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { - pendingResult: ReactServerDOMStaticServer.prerenderToNodeStream( - , - webpackMap, - { - signal: controller.signal, - onError(err) { - errors.push(err); + pendingResult: + ReactServerDOMStaticServer.unstable_prerenderToNodeStream( + , + webpackMap, + { + signal: controller.signal, + onError(err) { + errors.push(err); + }, }, - }, - ), + ), }; }); diff --git a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.browser.js b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.browser.js index d8373ec551bc0..c0860225d7b57 100644 --- a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.browser.js +++ b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.browser.js @@ -9,7 +9,7 @@ export { renderToReadableStream, - prerender, + prerender as unstable_prerender, decodeReply, decodeAction, decodeFormState, diff --git a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.browser.stable.js b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.browser.stable.js index 0100b65554aec..c0860225d7b57 100644 --- a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.browser.stable.js +++ b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.browser.stable.js @@ -9,6 +9,7 @@ export { renderToReadableStream, + prerender as unstable_prerender, decodeReply, decodeAction, decodeFormState, diff --git a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.edge.js b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.edge.js index 9521ba6b68841..48c4fc4553e6b 100644 --- a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.edge.js +++ b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.edge.js @@ -9,7 +9,7 @@ export { renderToReadableStream, - prerender, + prerender as unstable_prerender, decodeReply, decodeAction, decodeFormState, diff --git a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.edge.stable.js b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.edge.stable.js index eb887b73a8ae8..48c4fc4553e6b 100644 --- a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.edge.stable.js +++ b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.edge.stable.js @@ -9,6 +9,7 @@ export { renderToReadableStream, + prerender as unstable_prerender, decodeReply, decodeAction, decodeFormState, diff --git a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.js b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.js index badc2ed50b691..fde57467327b6 100644 --- a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.js +++ b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.js @@ -9,7 +9,7 @@ export { renderToPipeableStream, - prerenderToNodeStream, + prerenderToNodeStream as unstable_prerenderToNodeStream, decodeReplyFromBusboy, decodeReply, decodeAction, diff --git a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.stable.js b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.stable.js index 0d159704067ea..fde57467327b6 100644 --- a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.stable.js +++ b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.stable.js @@ -9,6 +9,7 @@ export { renderToPipeableStream, + prerenderToNodeStream as unstable_prerenderToNodeStream, decodeReplyFromBusboy, decodeReply, decodeAction, diff --git a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.unbundled.js b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.unbundled.js index badc2ed50b691..fde57467327b6 100644 --- a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.unbundled.js +++ b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.unbundled.js @@ -9,7 +9,7 @@ export { renderToPipeableStream, - prerenderToNodeStream, + prerenderToNodeStream as unstable_prerenderToNodeStream, decodeReplyFromBusboy, decodeReply, decodeAction, diff --git a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.unbundled.stable.js b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.unbundled.stable.js index 0d159704067ea..fde57467327b6 100644 --- a/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.unbundled.stable.js +++ b/packages/react-server-dom-webpack/src/server/react-flight-dom-server.node.unbundled.stable.js @@ -9,6 +9,7 @@ export { renderToPipeableStream, + prerenderToNodeStream as unstable_prerenderToNodeStream, decodeReplyFromBusboy, decodeReply, decodeAction, diff --git a/packages/react-server-dom-webpack/static.browser.js b/packages/react-server-dom-webpack/static.browser.js index 2589789163206..3281fed6ea29c 100644 --- a/packages/react-server-dom-webpack/static.browser.js +++ b/packages/react-server-dom-webpack/static.browser.js @@ -7,4 +7,4 @@ * @flow */ -export {prerender} from './src/server/react-flight-dom-server.browser'; +export {unstable_prerender} from './src/server/react-flight-dom-server.browser'; diff --git a/packages/react-server-dom-webpack/static.edge.js b/packages/react-server-dom-webpack/static.edge.js index a39d54c73f579..b1a96317ae9b3 100644 --- a/packages/react-server-dom-webpack/static.edge.js +++ b/packages/react-server-dom-webpack/static.edge.js @@ -7,4 +7,4 @@ * @flow */ -export {prerender} from './src/server/react-flight-dom-server.edge'; +export {unstable_prerender} from './src/server/react-flight-dom-server.edge'; diff --git a/packages/react-server-dom-webpack/static.node.js b/packages/react-server-dom-webpack/static.node.js index d15eddc6f9b0e..345f4123c9f09 100644 --- a/packages/react-server-dom-webpack/static.node.js +++ b/packages/react-server-dom-webpack/static.node.js @@ -7,4 +7,4 @@ * @flow */ -export {prerenderToNodeStream} from './src/server/react-flight-dom-server.node'; +export {unstable_prerenderToNodeStream} from './src/server/react-flight-dom-server.node'; diff --git a/packages/react-server-dom-webpack/static.node.unbundled.js b/packages/react-server-dom-webpack/static.node.unbundled.js index b2134459afc7a..35296ee12785a 100644 --- a/packages/react-server-dom-webpack/static.node.unbundled.js +++ b/packages/react-server-dom-webpack/static.node.unbundled.js @@ -7,4 +7,4 @@ * @flow */ -export {prerenderToNodeStream} from './src/server/react-flight-dom-server.node.unbundled'; +export {unstable_prerenderToNodeStream} from './src/server/react-flight-dom-server.node.unbundled'; From 16367ceb02faf5673e0380dec4c4928dfa37f17b Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Tue, 10 Dec 2024 16:11:17 -0500 Subject: [PATCH 2/3] [compiler] Fix dropped ref with spread props in InlineJsxTransform (#31726) When supporting ref as prop in https://github.com/facebook/react/pull/31558, I missed fixing the optimization to pass a spread-props-only props object in without an additional object copy. In the case that we have only a ref along with a spread, we cannot return only the spread object. This results in dropping the ref. In this example ```javascript ``` The bugged output is: ```javascript { // ... props: props } ``` With this change we now get the correct output: ```javascript { // ... props: {ref: ref, ...props} } ``` --- .../src/Optimization/InlineJsxTransform.ts | 8 ++-- .../compiler/inline-jsx-transform.expect.md | 39 +++++++++++++++++++ .../fixtures/compiler/inline-jsx-transform.js | 4 ++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts index 2851ed7ee39a1..9ffc64864f397 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts @@ -546,16 +546,14 @@ function createPropsProperties( let refProperty: ObjectProperty | undefined; let keyProperty: ObjectProperty | undefined; const props: Array = []; - const jsxAttributesWithoutKeyAndRef = propAttributes.filter( - p => p.kind === 'JsxAttribute' && p.name !== 'key' && p.name !== 'ref', + const jsxAttributesWithoutKey = propAttributes.filter( + p => p.kind === 'JsxAttribute' && p.name !== 'key', ); const jsxSpreadAttributes = propAttributes.filter( p => p.kind === 'JsxSpreadAttribute', ); const spreadPropsOnly = - jsxAttributesWithoutKeyAndRef.length === 0 && - jsxSpreadAttributes.length === 1; - + jsxAttributesWithoutKey.length === 0 && jsxSpreadAttributes.length === 1; propAttributes.forEach(prop => { switch (prop.kind) { case 'JsxAttribute': { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md index 91bd0ad0b750e..01b1470f93c8b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md @@ -60,6 +60,10 @@ function ConditionalJsx({shouldWrap}) { return content; } +function ComponentWithSpreadPropsAndRef({ref, ...other}) { + return ; +} + // TODO: Support value blocks function TernaryJsx({cond}) { return cond ?
: null; @@ -409,6 +413,41 @@ function ConditionalJsx(t0) { return content; } +function ComponentWithSpreadPropsAndRef(t0) { + const $ = _c2(6); + let other; + let ref; + if ($[0] !== t0) { + ({ ref, ...other } = t0); + $[0] = t0; + $[1] = other; + $[2] = ref; + } else { + other = $[1]; + ref = $[2]; + } + let t1; + if ($[3] !== other || $[4] !== ref) { + if (DEV) { + t1 = ; + } else { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Foo, + ref: ref, + key: null, + props: { ref: ref, ...other }, + }; + } + $[3] = other; + $[4] = ref; + $[5] = t1; + } else { + t1 = $[5]; + } + return t1; +} + // TODO: Support value blocks function TernaryJsx(t0) { const $ = _c2(2); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js index ca55cab4ff60a..2ab1efef794b6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js @@ -56,6 +56,10 @@ function ConditionalJsx({shouldWrap}) { return content; } +function ComponentWithSpreadPropsAndRef({ref, ...other}) { + return ; +} + // TODO: Support value blocks function TernaryJsx({cond}) { return cond ?
: null; From 7c4a7c9ddf2f1c8e223565af1256ea201ec0f303 Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Tue, 10 Dec 2024 23:46:33 +0200 Subject: [PATCH 3/3] react-hooks/rules-of-hooks: Improve support for `do/while` loops (#31720) --- .../__tests__/ESLintRulesOfHooks-test.js | 12 +++++++++++ .../src/RulesOfHooks.js | 20 ++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js b/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js index 4376d01d824a8..9152999f647c3 100644 --- a/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js +++ b/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js @@ -550,6 +550,18 @@ const tests = { // TODO: this should error but doesn't. // errors: [genericError('useState')], }, + { + code: normalizeIndent` + // Valid because the hook is outside of the loop + const Component = () => { + const [state, setState] = useState(0); + for (let i = 0; i < 10; i++) { + console.log(i); + } + return
; + }; + `, + }, ], invalid: [ { diff --git a/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js b/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js index 0b89390898ef4..bb80a24fba690 100644 --- a/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js +++ b/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js @@ -100,6 +100,16 @@ function isInsideComponentOrHook(node) { return false; } +function isInsideDoWhileLoop(node) { + while (node) { + if (node.type === 'DoWhileStatement') { + return true; + } + node = node.parent; + } + return false; +} + function isUseEffectEventIdentifier(node) { if (__EXPERIMENTAL__) { return node.type === 'Identifier' && node.name === 'useEffectEvent'; @@ -295,7 +305,7 @@ export default { if (pathList.has(segment.id)) { const pathArray = Array.from(pathList); const cyclicSegments = pathArray.slice( - pathArray.indexOf(segment.id) - 1, + pathArray.indexOf(segment.id) + 1, ); for (const cyclicSegment of cyclicSegments) { cyclic.add(cyclicSegment); @@ -485,7 +495,10 @@ export default { for (const hook of reactHooks) { // Report an error if a hook may be called more then once. // `use(...)` can be called in loops. - if (cycled && !isUseIdentifier(hook)) { + if ( + (cycled || isInsideDoWhileLoop(hook)) && + !isUseIdentifier(hook) + ) { context.report({ node: hook, message: @@ -520,7 +533,8 @@ export default { if ( !cycled && pathsFromStartToEnd !== allPathsFromStartToEnd && - !isUseIdentifier(hook) // `use(...)` can be called conditionally. + !isUseIdentifier(hook) && // `use(...)` can be called conditionally. + !isInsideDoWhileLoop(hook) // wrapping do/while loops are checked separately. ) { const message = `React Hook "${getSource(hook)}" is called ` +