From c4aeba91550c8bfacfb050246d4b98167cbd7da0 Mon Sep 17 00:00:00 2001 From: sebmarkbage Date: Mon, 12 Feb 2024 18:43:27 +0000 Subject: [PATCH] [Flight] Transfer Debug Info in Server-to-Server Flight Requests (#28275) A Flight Server can be a consumer of a stream from another Server. In this case the meta data is attached to debugInfo properties on lazy, Promises, Arrays or Elements that might in turn get forwarded to the next stream. In this case we want to forward this debug information to the client in the stream. I also added a DEV only `environmentName` option to the Flight Server. This lets you name the server that is producing the debug info so that you can trace the origin of where that component is executing. This defaults to `"server"`. DevTools could use this for badges or different colors. DiffTrain build for [629541bcc09fc7c0cc5c257541d084ee27457512](https://github.com/facebook/react/commit/629541bcc09fc7c0cc5c257541d084ee27457512) --- compiled/facebook-www/REVISION | 2 +- .../ReactDOMTesting-prod.modern.js | 6 +- .../ReactFlightDOMServer-dev.modern.js | 101 ++++++++++++++++-- .../ReactFlightDOMServer-prod.modern.js | 1 + .../ReactTestRenderer-dev.modern.js | 2 +- 5 files changed, 101 insertions(+), 11 deletions(-) diff --git a/compiled/facebook-www/REVISION b/compiled/facebook-www/REVISION index 360c034455..ea796b8fe4 100644 --- a/compiled/facebook-www/REVISION +++ b/compiled/facebook-www/REVISION @@ -1 +1 @@ -35b2c28178bf4f79898d11dce0bc2a7ce675f670 +629541bcc09fc7c0cc5c257541d084ee27457512 diff --git a/compiled/facebook-www/ReactDOMTesting-prod.modern.js b/compiled/facebook-www/ReactDOMTesting-prod.modern.js index d41f183fe6..9d57c647b9 100644 --- a/compiled/facebook-www/ReactDOMTesting-prod.modern.js +++ b/compiled/facebook-www/ReactDOMTesting-prod.modern.js @@ -17116,7 +17116,7 @@ Internals.Events = [ var devToolsConfig$jscomp$inline_1786 = { findFiberByHostInstance: getClosestInstanceFromNode, bundleType: 0, - version: "18.3.0-www-modern-6880028a", + version: "18.3.0-www-modern-9c7ddd0b", rendererPackageName: "react-dom" }; var internals$jscomp$inline_2162 = { @@ -17147,7 +17147,7 @@ var internals$jscomp$inline_2162 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-www-modern-6880028a" + reconcilerVersion: "18.3.0-www-modern-9c7ddd0b" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_2163 = __REACT_DEVTOOLS_GLOBAL_HOOK__; @@ -17575,4 +17575,4 @@ exports.useFormStatus = function () { return ReactCurrentDispatcher$2.current.useHostTransitionStatus(); throw Error(formatProdErrorMessage(248)); }; -exports.version = "18.3.0-www-modern-6880028a"; +exports.version = "18.3.0-www-modern-9c7ddd0b"; diff --git a/compiled/facebook-www/ReactFlightDOMServer-dev.modern.js b/compiled/facebook-www/ReactFlightDOMServer-dev.modern.js index c0b2e0d3ad..dfc1325cbb 100644 --- a/compiled/facebook-www/ReactFlightDOMServer-dev.modern.js +++ b/compiled/facebook-www/ReactFlightDOMServer-dev.modern.js @@ -1104,7 +1104,8 @@ if (__DEV__) { bundlerConfig, onError, identifierPrefix, - onPostpone + onPostpone, + environmentName ) { if ( ReactCurrentCache.current !== null && @@ -1149,6 +1150,12 @@ if (__DEV__) { onPostpone: onPostpone === undefined ? defaultPostponeHandler : onPostpone }; + + { + request.environmentName = + environmentName === undefined ? "server" : environmentName; + } + var rootTask = createTask(request, model, null, false, abortSet); pingedTasks.push(rootTask); return request; @@ -1169,6 +1176,15 @@ if (__DEV__) { request.abortableTasks ); + { + // If this came from Flight, forward any debug info into this new row. + var debugInfo = thenable._debugInfo; + + if (debugInfo) { + forwardDebugInfo(request, newTask.id, debugInfo); + } + } + switch (thenable.status) { case "fulfilled": { // We have the resolved value, we can go ahead and schedule it for serialization. @@ -1308,6 +1324,12 @@ if (__DEV__) { _payload: thenable, _init: readThenable }; + + { + // If this came from React, transfer the debug info. + lazyType._debugInfo = thenable._debugInfo || []; + } + return lazyType; } @@ -1329,7 +1351,8 @@ if (__DEV__) { var componentName = Component.displayName || Component.name || ""; request.pendingChunks++; emitDebugChunk(request, debugID, { - name: componentName + name: componentName, + env: request.environmentName }); } } @@ -1378,6 +1401,24 @@ if (__DEV__) { } function renderFragment(request, task, children) { + { + var debugInfo = children._debugInfo; + + if (debugInfo) { + // If this came from Flight, forward any debug info into this new row. + if (debugID === null) { + // We don't have a chunk to assign debug info. We need to outline this + // component to assign it an ID. + return outlineTask(request, task); + } else { + // Forward any debug info we have the first time we see it. + // We do this after init so that we have received all the debug info + // from the server by the time we emit it. + forwardDebugInfo(request, debugID, debugInfo); + } + } + } + if (task.keyPath !== null) { // We have a Server Component that specifies a key but we're now splitting // the tree using a fragment. @@ -1969,7 +2010,23 @@ if (__DEV__) { _writtenObjects.set(value, -1); } - var element = value; // Attempt to render the Server Component. + var element = value; + + { + var debugInfo = value._debugInfo; + + if (debugInfo) { + // If this came from Flight, forward any debug info into this new row. + if (debugID === null) { + // We don't have a chunk to assign debug info. We need to outline this + // component to assign it an ID. + return outlineTask(request, task); + } else { + // Forward any debug info we have the first time we see it. + forwardDebugInfo(request, debugID, debugInfo); + } + } + } // Attempt to render the Server Component. return renderElement( request, @@ -1982,9 +2039,32 @@ if (__DEV__) { } case REACT_LAZY_TYPE: { - var payload = value._payload; - var init = value._init; + // Reset the task's thenable state before continuing. If there was one, it was + // from suspending the lazy before. + task.thenableState = null; + var lazy = value; + var payload = lazy._payload; + var init = lazy._init; var resolvedModel = init(payload); + + { + var _debugInfo = lazy._debugInfo; + + if (_debugInfo) { + // If this came from Flight, forward any debug info into this new row. + if (debugID === null) { + // We don't have a chunk to assign debug info. We need to outline this + // component to assign it an ID. + return outlineTask(request, task); + } else { + // Forward any debug info we have the first time we see it. + // We do this after init so that we have received all the debug info + // from the server by the time we emit it. + forwardDebugInfo(request, debugID, _debugInfo); + } + } + } + return renderModelDestructive( request, task, @@ -2310,6 +2390,13 @@ if (__DEV__) { request.completedRegularChunks.push(processedChunk); } + function forwardDebugInfo(request, id, debugInfo) { + for (var i = 0; i < debugInfo.length; i++) { + request.pendingChunks++; + emitDebugChunk(request, id, debugInfo[i]); + } + } + var emptyRoot = {}; function retryTask(request, task) { @@ -2578,7 +2665,9 @@ if (__DEV__) { var request = createRequest( model, null, - options ? options.onError : undefined + options ? options.onError : undefined, + undefined, + undefined ); startWork(request); startFlowing(request, destination); diff --git a/compiled/facebook-www/ReactFlightDOMServer-prod.modern.js b/compiled/facebook-www/ReactFlightDOMServer-prod.modern.js index 0f49ccc376..037b4a4a64 100644 --- a/compiled/facebook-www/ReactFlightDOMServer-prod.modern.js +++ b/compiled/facebook-www/ReactFlightDOMServer-prod.modern.js @@ -797,6 +797,7 @@ function renderModelDestructive( ); case REACT_LAZY_TYPE: return ( + (task.thenableState = null), (parent = value._init), (value = parent(value._payload)), renderModelDestructive(request, task, emptyRoot, "", value) diff --git a/compiled/facebook-www/ReactTestRenderer-dev.modern.js b/compiled/facebook-www/ReactTestRenderer-dev.modern.js index 809fe4a3d0..1be3e46d08 100644 --- a/compiled/facebook-www/ReactTestRenderer-dev.modern.js +++ b/compiled/facebook-www/ReactTestRenderer-dev.modern.js @@ -26096,7 +26096,7 @@ if (__DEV__) { return root; } - var ReactVersion = "18.3.0-www-modern-623a68d9"; + var ReactVersion = "18.3.0-www-modern-f687cbe4"; // Might add PROFILE later.