From 0850c4ccf3e30911b3fb038f74cbbb0069a714b4 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 24 Feb 2022 15:49:48 -0500 Subject: [PATCH 1/4] Deprecate renderToNodeStream --- packages/react-dom/src/server/ReactDOMLegacyServerNode.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/react-dom/src/server/ReactDOMLegacyServerNode.js b/packages/react-dom/src/server/ReactDOMLegacyServerNode.js index 71ebab5ac0f..fd55b2b0a5c 100644 --- a/packages/react-dom/src/server/ReactDOMLegacyServerNode.js +++ b/packages/react-dom/src/server/ReactDOMLegacyServerNode.js @@ -93,6 +93,11 @@ function renderToNodeStream( children: ReactNodeList, options?: ServerOptions, ): Readable { + if (__DEV__) { + console.error( + 'renderToNodeStream is deprecated. Use renderToPipeableStream instead.', + ); + } return renderToNodeStreamImpl(children, options, false); } From f62de1d8e3cc24a27f36147fe7a45d0d00695745 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 24 Feb 2022 15:52:38 -0500 Subject: [PATCH 2/4] Use renderToPipeableStream in tests instead of renderToNodeStream This is the equivalent API. This means that we have way less test coverage of this API but I feel like that's fine since it has a deprecation warning in it and we have coverage on renderToString that is mostly the same. --- ...eactDOMServerIntegrationNewContext-test.js | 46 ++++++++++++++----- .../__tests__/ReactServerRendering-test.js | 16 ++++++- .../ReactDOMServerIntegrationTestUtils.js | 14 ++++-- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js index 85c21406753..4d1016dfdac 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js @@ -409,12 +409,24 @@ describe('ReactDOMServerIntegration', () => { ); - const streamAmy = ReactDOMServer.renderToNodeStream( - AppWithUser('Amy'), - ).setEncoding('utf8'); - const streamBob = ReactDOMServer.renderToNodeStream( - AppWithUser('Bob'), - ).setEncoding('utf8'); + let streamAmy; + let streamBob; + expect(() => { + streamAmy = ReactDOMServer.renderToNodeStream( + AppWithUser('Amy'), + ).setEncoding('utf8'); + }).toErrorDev( + 'renderToNodeStream is deprecated. Use renderToPipeableStream instead.', + {withoutStack: true}, + ); + expect(() => { + streamBob = ReactDOMServer.renderToNodeStream( + AppWithUser('Bob'), + ).setEncoding('utf8'); + }).toErrorDev( + 'renderToNodeStream is deprecated. Use renderToPipeableStream instead.', + {withoutStack: true}, + ); // Testing by filling the buffer using internal _read() with a small // number of bytes to avoid a test case which needs to align to a @@ -449,9 +461,14 @@ describe('ReactDOMServerIntegration', () => { const streamCount = 34; for (let i = 0; i < streamCount; i++) { - streams[i] = ReactDOMServer.renderToNodeStream( - NthRender(i % 2 === 0 ? 'Expected to be recreated' : i), - ).setEncoding('utf8'); + expect(() => { + streams[i] = ReactDOMServer.renderToNodeStream( + NthRender(i % 2 === 0 ? 'Expected to be recreated' : i), + ).setEncoding('utf8'); + }).toErrorDev( + 'renderToNodeStream is deprecated. Use renderToPipeableStream instead.', + {withoutStack: true}, + ); } // Testing by filling the buffer using internal _read() with a small @@ -468,9 +485,14 @@ describe('ReactDOMServerIntegration', () => { // Recreate those same streams. for (let i = 0; i < streamCount; i += 2) { - streams[i] = ReactDOMServer.renderToNodeStream( - NthRender(i), - ).setEncoding('utf8'); + expect(() => { + streams[i] = ReactDOMServer.renderToNodeStream( + NthRender(i), + ).setEncoding('utf8'); + }).toErrorDev( + 'renderToNodeStream is deprecated. Use renderToPipeableStream instead.', + {withoutStack: true}, + ); } // Read a bit from all streams again. diff --git a/packages/react-dom/src/__tests__/ReactServerRendering-test.js b/packages/react-dom/src/__tests__/ReactServerRendering-test.js index 6489151b055..0c057c5fade 100644 --- a/packages/react-dom/src/__tests__/ReactServerRendering-test.js +++ b/packages/react-dom/src/__tests__/ReactServerRendering-test.js @@ -569,7 +569,13 @@ describe('ReactDOMServer', () => { describe('renderToNodeStream', () => { it('should generate simple markup', () => { const SuccessfulElement = React.createElement(() => ); - const response = ReactDOMServer.renderToNodeStream(SuccessfulElement); + let response; + expect(() => { + response = ReactDOMServer.renderToNodeStream(SuccessfulElement); + }).toErrorDev( + 'renderToNodeStream is deprecated. Use renderToPipeableStream instead.', + {withoutStack: true}, + ); expect(response.read().toString()).toMatch(new RegExp('')); }); @@ -577,7 +583,13 @@ describe('ReactDOMServer', () => { const FailingElement = React.createElement(() => { throw new Error('An Error'); }); - const response = ReactDOMServer.renderToNodeStream(FailingElement); + let response; + expect(() => { + response = ReactDOMServer.renderToNodeStream(FailingElement); + }).toErrorDev( + 'renderToNodeStream is deprecated. Use renderToPipeableStream instead.', + {withoutStack: true}, + ); return new Promise(resolve => { response.once('error', () => { resolve(); diff --git a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js index 8714059bb38..9f23d7aa96a 100644 --- a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js +++ b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js @@ -154,8 +154,11 @@ module.exports = function(initModules) { () => new Promise((resolve, reject) => { const writable = new DrainWritable(); - const s = ReactDOMServer.renderToNodeStream(reactElement); - s.on('error', e => reject(e)); + const s = ReactDOMServer.renderToPipeableStream(reactElement, { + onErrorShell(e) { + reject(e); + }, + }); s.pipe(writable); writable.on('finish', () => resolve(writable.buffer)); }), @@ -168,7 +171,12 @@ module.exports = function(initModules) { // Does not render on client or perform client-side revival. async function streamRender(reactElement, errorCount = 0) { const markup = await renderIntoStream(reactElement, errorCount); - return getContainerFromMarkup(reactElement, markup).firstChild; + let firstNode = getContainerFromMarkup(reactElement, markup).firstChild; + if (firstNode && firstNode.nodeType === Node.DOCUMENT_TYPE_NODE) { + // Skip document type nodes. + firstNode = firstNode.nextSibling; + } + return firstNode; } const clientCleanRender = (element, errorCount = 0) => { From e915eee9fcc56cfbfe42f7e4b50d6cf3b9db9c6b Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 24 Feb 2022 17:49:12 -0500 Subject: [PATCH 3/4] Fix textarea bug The test changes revealed a bug with textarea. It happens because we currently always insert trailing comment nodes. We should optimize that away. However, we also don't really support complex children so we should toString it anyway which is what partial renderer used to do. --- .../ReactDOMServerIntegrationTextarea-test.js | 6 ++++++ .../src/server/ReactDOMServerFormatConfig.js | 12 +++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js index 261b6c04149..1d8b388c4b3 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js @@ -49,6 +49,12 @@ describe('ReactDOMServerIntegrationTextarea', () => { expect(e.value).toBe('foo'); }); + itRenders('a textarea with a value of undefined', async render => { + const e = await render(