diff --git a/compiled/facebook-www/REVISION b/compiled/facebook-www/REVISION index 18a2771d8fa38..e3ad4095d63d1 100644 --- a/compiled/facebook-www/REVISION +++ b/compiled/facebook-www/REVISION @@ -1 +1 @@ -cb2439624f43c510007f65aea5c50a8bb97917e4 +0cdfef19b96cc6202d48e0812b5069c286d12b04 diff --git a/compiled/facebook-www/React-dev.modern.js b/compiled/facebook-www/React-dev.modern.js index 0b800fe93e5d5..857c0430df6e6 100644 --- a/compiled/facebook-www/React-dev.modern.js +++ b/compiled/facebook-www/React-dev.modern.js @@ -24,7 +24,7 @@ if (__DEV__) { ) { __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); } - var ReactVersion = "18.3.0-www-modern-2525a22c"; + var ReactVersion = "18.3.0-www-modern-7daa3def"; // ATTENTION // When adding new symbols to this file, diff --git a/compiled/facebook-www/ReactDOMServer-dev.classic.js b/compiled/facebook-www/ReactDOMServer-dev.classic.js index 9993a0447d2a8..cb611fad071b5 100644 --- a/compiled/facebook-www/ReactDOMServer-dev.classic.js +++ b/compiled/facebook-www/ReactDOMServer-dev.classic.js @@ -19,7 +19,7 @@ if (__DEV__) { var React = require("react"); var ReactDOM = require("react-dom"); - var ReactVersion = "18.3.0-www-classic-806ab62c"; + var ReactVersion = "18.3.0-www-classic-4929d908"; // This refers to a WWW module. var warningWWW = require("warning"); @@ -10833,8 +10833,7 @@ if (__DEV__) { rootFormatContext, emptyContextObject, rootContextSnapshot, - emptyTreeContext, - null + emptyTreeContext ); pingedTasks.push(rootTask); return request; @@ -10886,8 +10885,7 @@ if (__DEV__) { formatContext, legacyContext, context, - treeContext, - componentStack + treeContext ) { request.allPendingTasks++; @@ -10912,9 +10910,13 @@ if (__DEV__) { legacyContext: legacyContext, context: context, treeContext: treeContext, - componentStack: componentStack, thenableState: thenableState }; + + { + task.componentStack = null; + } + abortSet.add(task); return task; } @@ -10931,8 +10933,7 @@ if (__DEV__) { formatContext, legacyContext, context, - treeContext, - componentStack + treeContext ) { request.allPendingTasks++; @@ -10958,9 +10959,13 @@ if (__DEV__) { legacyContext: legacyContext, context: context, treeContext: treeContext, - componentStack: componentStack, thenableState: thenableState }; + + { + task.componentStack = null; + } + abortSet.add(task); return task; } @@ -11003,52 +11008,52 @@ if (__DEV__) { } } - function getStackFromNode(stackNode) { - return getStackByComponentStackNode(stackNode); - } - - function createBuiltInComponentStack(task, type) { - return { - tag: 0, - parent: task.componentStack, - type: type - }; + function pushBuiltInComponentStackInDEV(task, type) { + { + task.componentStack = { + tag: 0, + parent: task.componentStack, + type: type + }; + } } - function createFunctionComponentStack(task, type) { - return { - tag: 1, - parent: task.componentStack, - type: type - }; + function pushFunctionComponentStackInDEV(task, type) { + { + task.componentStack = { + tag: 1, + parent: task.componentStack, + type: type + }; + } } - function createClassComponentStack(task, type) { - return { - tag: 2, - parent: task.componentStack, - type: type - }; - } // While we track component stacks in prod all the time we only produce a reified stack in dev and - // during prerender in Prod. The reason for this is that the stack is useful for prerender where the timeliness - // of the request is less critical than the observability of the execution. For renders and resumes however we - // prioritize speed of the request. - - function getThrownInfo(node) { - if (node) { - return { - componentStack: getStackFromNode(node) + function pushClassComponentStackInDEV(task, type) { + { + task.componentStack = { + tag: 2, + parent: task.componentStack, + type: type }; - } else { - return {}; } } - function encodeErrorForBoundary(boundary, digest, error, thrownInfo) { - boundary.errorDigest = digest; + function popComponentStackInDEV(task) { + { + if (task.componentStack === null) { + error( + "Unexpectedly popped too many stack frames. This is a bug in React." + ); + } else { + task.componentStack = task.componentStack.parent; + } + } + } // stash the component stack of an unwinding error until it is processed + + var lastBoundaryErrorComponentStackDev = null; + function captureBoundaryErrorDetailsDev(boundary, error) { { - // In dev we additionally encode the error message and component stack on the boundary var errorMessage; if (typeof error === "string") { @@ -11060,27 +11065,26 @@ if (__DEV__) { errorMessage = String(error); } + var errorComponentStack = + lastBoundaryErrorComponentStackDev || getCurrentStackInDEV(); + lastBoundaryErrorComponentStackDev = null; boundary.errorMessage = errorMessage; - boundary.errorComponentStack = thrownInfo.componentStack; + boundary.errorComponentStack = errorComponentStack; } } - function logRecoverableError(request, error$1, errorInfo) { + function logRecoverableError(request, error) { // If this callback errors, we intentionally let that error bubble up to become a fatal error // so that someone fixes the error reporting instead of hiding it. - var errorDigest = request.onError(error$1, errorInfo); + var errorDigest = request.onError(error); if (errorDigest != null && typeof errorDigest !== "string") { - // We used to throw here but since this gets called from a variety of unprotected places it - // seems better to just warn and discard the returned value. - { - error( - 'onError returned something with a type other than "string". onError should return a string and may return null or undefined but must not return anything else. It received something of type "%s" instead', - typeof errorDigest - ); - } - - return; + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error( + 'onError returned something with a type other than "string". onError should return a string and may return null or undefined but must not return anything else. It received something of type "' + + typeof errorDigest + + '" instead' + ); } return errorDigest; @@ -11123,11 +11127,7 @@ if (__DEV__) { } // $FlowFixMe: Refined. var task = someTask; - var previousComponentStack = task.componentStack; // If we end up creating the fallback task we need it to have the correct stack which is - // the stack for the boundary itself. We stash it here so we can use it if needed later - - var suspenseComponentStack = (task.componentStack = - createBuiltInComponentStack(task, "Suspense")); + pushBuiltInComponentStackInDEV(task, "Suspense"); var prevKeyPath = task.keyPath; var parentBoundary = task.blockedBoundary; var parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for @@ -11201,25 +11201,27 @@ if (__DEV__) { queueCompletedSegment(newBoundary, contentRootSegment); if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) { - // This must have been the last segment we were waiting on. This boundary is now complete. + newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete. // Therefore we won't need the fallback. We early return so that we don't have to create // the fallback. - newBoundary.status = COMPLETED; // We are returning early so we need to restore the - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); return; } } catch (error) { contentRootSegment.status = ERRORED; newBoundary.status = CLIENT_RENDERED; - var thrownInfo = getThrownInfo(task.componentStack); var errorDigest; { - errorDigest = logRecoverableError(request, error, thrownInfo); + errorDigest = logRecoverableError(request, error); } - encodeErrorForBoundary(newBoundary, errorDigest, error, thrownInfo); // We don't need to decrement any task numbers because we didn't spawn any new task. + newBoundary.errorDigest = errorDigest; + + { + captureBoundaryErrorDetailsDev(newBoundary, error); + } // We don't need to decrement any task numbers because we didn't spawn any new task. // We don't need to schedule any task because we know the parent has written yet. // We do need to fallthrough to create the fallback though. } finally { @@ -11233,7 +11235,6 @@ if (__DEV__) { task.blockedBoundary = parentBoundary; task.blockedSegment = parentSegment; task.keyPath = prevKeyPath; - task.componentStack = previousComponentStack; } var fallbackKeyPath = [keyPath[0], "Suspense Fallback", keyPath[2]]; @@ -11273,13 +11274,16 @@ if (__DEV__) { task.formatContext, task.legacyContext, task.context, - task.treeContext, // This stack should be the Suspense boundary stack because while the fallback is actually a child segment - // of the parent boundary from a component standpoint the fallback is a child of the Suspense boundary itself - suspenseComponentStack - ); // TODO: This should be queued at a separate lower priority queue so that we only work + task.treeContext + ); + + { + suspendedFallbackTask.componentStack = task.componentStack; + } // TODO: This should be queued at a separate lower priority queue so that we only work // on preparing fallbacks if we don't have any more main content to task on. request.pingedTasks.push(suspendedFallbackTask); + popComponentStackInDEV(task); } function replaySuspenseBoundary( @@ -11293,11 +11297,7 @@ if (__DEV__) { fallbackNodes, fallbackSlots ) { - var previousComponentStack = task.componentStack; // If we end up creating the fallback task we need it to have the correct stack which is - // the stack for the boundary itself. We stash it here so we can use it if needed later - - var suspenseComponentStack = (task.componentStack = - createBuiltInComponentStack(task, "Suspense")); + pushBuiltInComponentStackInDEV(task, "Suspense"); var prevKeyPath = task.keyPath; var previousReplaySet = task.replay; var parentBoundary = task.blockedBoundary; @@ -11342,26 +11342,28 @@ if (__DEV__) { resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING ) { - // This must have been the last segment we were waiting on. This boundary is now complete. + resumedBoundary.status = COMPLETED; + request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete. // Therefore we won't need the fallback. We early return so that we don't have to create // the fallback. - resumedBoundary.status = COMPLETED; - request.completedBoundaries.push(resumedBoundary); // We restore the parent componentStack. Semantically this is the same as - // popComponentStack(task) but we do this instead because it should be slightly - // faster + popComponentStackInDEV(task); return; } } catch (error) { resumedBoundary.status = CLIENT_RENDERED; - var thrownInfo = getThrownInfo(task.componentStack); var errorDigest; { - errorDigest = logRecoverableError(request, error, thrownInfo); + errorDigest = logRecoverableError(request, error); + } + + resumedBoundary.errorDigest = errorDigest; + + { + captureBoundaryErrorDetailsDev(resumedBoundary, error); } - encodeErrorForBoundary(resumedBoundary, errorDigest, error, thrownInfo); task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted. request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task. @@ -11378,7 +11380,6 @@ if (__DEV__) { task.blockedBoundary = parentBoundary; task.replay = previousReplaySet; task.keyPath = prevKeyPath; - task.componentStack = previousComponentStack; } var fallbackKeyPath = [keyPath[0], "Suspense Fallback", keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work @@ -11401,18 +11402,20 @@ if (__DEV__) { task.formatContext, task.legacyContext, task.context, - task.treeContext, // This stack should be the Suspense boundary stack because while the fallback is actually a child segment - // of the parent boundary from a component standpoint the fallback is a child of the Suspense boundary itself - suspenseComponentStack - ); // TODO: This should be queued at a separate lower priority queue so that we only work + task.treeContext + ); + + { + suspendedFallbackTask.componentStack = task.componentStack; + } // TODO: This should be queued at a separate lower priority queue so that we only work // on preparing fallbacks if we don't have any more main content to task on. request.pingedTasks.push(suspendedFallbackTask); + popComponentStackInDEV(task); } function renderHostElement(request, task, keyPath, type, props) { - var previousComponentStack = task.componentStack; - task.componentStack = createBuiltInComponentStack(task, type); + pushBuiltInComponentStackInDEV(task, type); var segment = task.blockedSegment; if (segment === null) { @@ -11464,7 +11467,7 @@ if (__DEV__) { segment.lastPushedText = false; } - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); } function shouldConstruct(Component) { @@ -11541,13 +11544,12 @@ if (__DEV__) { } function renderClassComponent(request, task, keyPath, Component, props) { - var previousComponentStack = task.componentStack; - task.componentStack = createClassComponentStack(task, Component); + pushClassComponentStackInDEV(task, Component); var maskedContext = getMaskedContext(Component, task.legacyContext); var instance = constructClassInstance(Component, props, maskedContext); mountClassInstance(instance, Component, props, maskedContext); finishClassComponent(request, task, keyPath, instance, Component, props); - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); } var didWarnAboutBadClass = {}; @@ -11575,8 +11577,7 @@ if (__DEV__) { legacyContext = getMaskedContext(Component, task.legacyContext); } - var previousComponentStack = task.componentStack; - task.componentStack = createFunctionComponentStack(task, Component); + pushFunctionComponentStackInDEV(task, Component); { if ( @@ -11655,7 +11656,7 @@ if (__DEV__) { ); } - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); } function finishFunctionComponent( @@ -11813,8 +11814,7 @@ if (__DEV__) { props, ref ) { - var previousComponentStack = task.componentStack; - task.componentStack = createFunctionComponentStack(task, type.render); + pushFunctionComponentStackInDEV(task, type.render); var children = renderWithHooks( request, task, @@ -11836,7 +11836,7 @@ if (__DEV__) { formStateCount, formStateMatchingIndex ); - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); } function renderMemo( @@ -11945,8 +11945,7 @@ if (__DEV__) { props, ref ) { - var previousComponentStack = task.componentStack; - task.componentStack = createBuiltInComponentStack(task, "Lazy"); + pushBuiltInComponentStackInDEV(task, "Lazy"); var payload = lazyComponent._payload; var init = lazyComponent._init; var Component = init(payload); @@ -11960,7 +11959,7 @@ if (__DEV__) { resolvedProps, ref ); - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); } function renderOffscreen(request, task, keyPath, props) { @@ -12036,17 +12035,13 @@ if (__DEV__) { } case REACT_SUSPENSE_LIST_TYPE: { - var preiousComponentStack = task.componentStack; - task.componentStack = createBuiltInComponentStack( - task, - "SuspenseList" - ); // TODO: SuspenseList should control the boundaries. + pushBuiltInComponentStackInDEV(task, "SuspenseList"); // TODO: SuspenseList should control the boundaries. var _prevKeyPath3 = task.keyPath; task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); task.keyPath = _prevKeyPath3; - task.componentStack = preiousComponentStack; + popComponentStackInDEV(task); return; } @@ -12272,12 +12267,10 @@ if (__DEV__) { // replay nodes which might be Suspense boundaries which are able to // absorb the error and we can still continue with siblings. - var thrownInfo = getThrownInfo(task.componentStack); erroredReplay( request, task.blockedBoundary, x, - thrownInfo, childNodes, childSlots ); @@ -12350,8 +12343,7 @@ if (__DEV__) { didWarnAboutMaps = true; } } - } // This function by it self renders a node and consumes the task by mutating it - // to update the current execution state. + } function renderNodeDestructive( request, @@ -12360,6 +12352,45 @@ if (__DEV__) { prevThenableState, node, childIndex + ) { + { + // In Dev we wrap renderNodeDestructiveImpl in a try / catch so we can capture + // a component stack at the right place in the tree. We don't do this in renderNode + // becuase it is not called at every layer of the tree and we may lose frames + try { + return renderNodeDestructiveImpl( + request, + task, + prevThenableState, + node, + childIndex + ); + } catch (x) { + if ( + typeof x === "object" && + x !== null && + typeof x.then === "function" + ); + else { + // This is an error, stash the component stack if it is null. + lastBoundaryErrorComponentStackDev = + lastBoundaryErrorComponentStackDev !== null + ? lastBoundaryErrorComponentStackDev + : getCurrentStackInDEV(); + } // rethrow so normal suspense logic can handle thrown value accordingly + + throw x; + } + } + } // This function by it self renders a node and consumes the task by mutating it + // to update the current execution state. + + function renderNodeDestructiveImpl( + request, + task, + prevThenableState, + node, + childIndex ) { if (task.replay !== null && typeof task.replay.slots === "number") { // TODO: Figure out a cheaper place than this hot path to do this check. @@ -12423,15 +12454,30 @@ if (__DEV__) { ); case REACT_LAZY_TYPE: { - var previousComponentStack = task.componentStack; - task.componentStack = createBuiltInComponentStack(task, "Lazy"); var lazyNode = node; var payload = lazyNode._payload; var init = lazyNode._init; - var resolvedNode = init(payload); // We restore the stack before rendering the resolved node because once the Lazy - // has resolved any future errors + var resolvedNode; - task.componentStack = previousComponentStack; // Now we render the resolved node + { + try { + resolvedNode = init(payload); + } catch (x) { + if ( + typeof x === "object" && + x !== null && + typeof x.then === "function" + ) { + // this Lazy initializer is suspending. push a temporary frame onto the stack so it can be + // popped off in spawnNewSuspendedTask. This aligns stack behavior between Lazy in element position + // vs Component position. We do not want the frame for Errors so we exclusively do this in + // the wakeable branch + pushBuiltInComponentStackInDEV(task, "Lazy"); + } + + throw x; + } + } renderNodeDestructive( request, @@ -12494,7 +12540,7 @@ if (__DEV__) { if (typeof maybeUsable.then === "function") { var thenable = maybeUsable; - return renderNodeDestructive( + return renderNodeDestructiveImpl( request, task, null, @@ -12508,7 +12554,7 @@ if (__DEV__) { maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE ) { var context = maybeUsable; - return renderNodeDestructive( + return renderNodeDestructiveImpl( request, task, null, @@ -12621,12 +12667,10 @@ if (__DEV__) { // absorb the error and we can still continue with siblings. // This is an error, stash the component stack if it is null. - var thrownInfo = getThrownInfo(task.componentStack); erroredReplay( request, task.blockedBoundary, x, - thrownInfo, childNodes, childSlots ); @@ -12720,10 +12764,17 @@ if (__DEV__) { task.formatContext, task.legacyContext, task.context, - task.treeContext, // We pop one task off the stack because the node that suspended will be tried again, - // which will add it back onto the stack. - task.componentStack !== null ? task.componentStack.parent : null + task.treeContext ); + + { + if (task.componentStack !== null) { + // We pop one task off the stack because the node that suspended will be tried again, + // which will add it back onto the stack. + newTask.componentStack = task.componentStack.parent; + } + } + var ping = newTask.ping; x.then(ping, ping); } @@ -12755,10 +12806,17 @@ if (__DEV__) { task.formatContext, task.legacyContext, task.context, - task.treeContext, // We pop one task off the stack because the node that suspended will be tried again, - // which will add it back onto the stack. - task.componentStack !== null ? task.componentStack.parent : null + task.treeContext ); + + { + if (task.componentStack !== null) { + // We pop one task off the stack because the node that suspended will be tried again, + // which will add it back onto the stack. + newTask.componentStack = task.componentStack.parent; + } + } + var ping = newTask.ping; x.then(ping, ping); } // This is a non-destructive form of rendering a node. If it suspends it spawns @@ -12772,7 +12830,12 @@ if (__DEV__) { var previousContext = task.context; var previousKeyPath = task.keyPath; var previousTreeContext = task.treeContext; - var previousComponentStack = task.componentStack; + var previousComponentStack = null; + + { + previousComponentStack = task.componentStack; + } + var x; // Store how much we've pushed at this point so we can reset it in case something // suspended partially through writing something. @@ -12810,10 +12873,14 @@ if (__DEV__) { task.legacyContext = previousLegacyContext; task.context = previousContext; task.keyPath = previousKeyPath; - task.treeContext = previousTreeContext; - task.componentStack = previousComponentStack; // Restore all active ReactContexts to what they were before. + task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before. switchContext(previousContext); + + { + task.componentStack = previousComponentStack; + } + return; } } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode. @@ -12858,10 +12925,14 @@ if (__DEV__) { task.legacyContext = previousLegacyContext; task.context = previousContext; task.keyPath = previousKeyPath; - task.treeContext = previousTreeContext; - task.componentStack = previousComponentStack; // Restore all active ReactContexts to what they were before. + task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before. switchContext(previousContext); + + { + task.componentStack = previousComponentStack; + } + return; } } @@ -12873,23 +12944,19 @@ if (__DEV__) { task.legacyContext = previousLegacyContext; task.context = previousContext; task.keyPath = previousKeyPath; - task.treeContext = previousTreeContext; // We intentionally do not restore the component stack on the error pathway - // Whatever handles the error needs to use this stack which is the location of the - // error. We must restore the stack wherever we handle this - // Restore all active ReactContexts to what they were before. + task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before. switchContext(previousContext); + + { + task.componentStack = previousComponentStack; + } // We assume that we don't need the correct context. + // Let's terminate the rest of the tree and don't render any siblings. + throw x; } - function erroredReplay( - request, - boundary, - error, - errorInfo, - replayNodes, - resumeSlots - ) { + function erroredReplay(request, boundary, error, replayNodes, resumeSlots) { // Erroring during a replay doesn't actually cause an error by itself because // that component has already rendered. What causes the error is the resumable // points that we did not yet finish which will be below the point of the reset. @@ -12900,7 +12967,7 @@ if (__DEV__) { var errorDigest; { - errorDigest = logRecoverableError(request, error, errorInfo); + errorDigest = logRecoverableError(request, error); } abortRemainingReplayNodes( @@ -12909,27 +12976,31 @@ if (__DEV__) { replayNodes, resumeSlots, error, - errorDigest, - errorInfo + errorDigest ); } - function erroredTask(request, boundary, error, errorInfo) { + function erroredTask(request, boundary, error) { // Report the error to a global handler. var errorDigest; { - errorDigest = logRecoverableError(request, error, errorInfo); + errorDigest = logRecoverableError(request, error); } if (boundary === null) { + lastBoundaryErrorComponentStackDev = null; fatalError(request, error); } else { boundary.pendingTasks--; if (boundary.status !== CLIENT_RENDERED) { boundary.status = CLIENT_RENDERED; - encodeErrorForBoundary(boundary, errorDigest, error, errorInfo); // Regardless of what happens next, this boundary won't be displayed, + boundary.errorDigest = errorDigest; + + { + captureBoundaryErrorDetailsDev(boundary, error); + } // Regardless of what happens next, this boundary won't be displayed, // so we can flush it, if the parent already flushed. if (boundary.parentFlushed) { @@ -12939,6 +13010,8 @@ if (__DEV__) { // We reuse the same queue for errors. request.clientRenderedBoundaries.push(boundary); } + } else { + lastBoundaryErrorComponentStackDev = null; } } @@ -12967,18 +13040,18 @@ if (__DEV__) { request, rootSegmentID, error, - errorDigest, - errorInfo + errorDigest ) { var resumedBoundary = createSuspenseBoundary(request, new Set()); resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender. resumedBoundary.rootSegmentID = rootSegmentID; resumedBoundary.status = CLIENT_RENDERED; - var errorMessage = error; + resumedBoundary.errorDigest = errorDigest; { var errorPrefix = "The server did not finish this Suspense boundary: "; + var errorMessage; if (error && typeof error.message === "string") { errorMessage = errorPrefix + error.message; @@ -12986,14 +13059,16 @@ if (__DEV__) { // eslint-disable-next-line react-internal/safe-string-coercion errorMessage = errorPrefix + String(error); } - } - encodeErrorForBoundary( - resumedBoundary, - errorDigest, - errorMessage, - errorInfo - ); + var previousTaskInDev = currentTaskInDEV; + currentTaskInDEV = null; + + try { + captureBoundaryErrorDetailsDev(resumedBoundary, errorMessage); + } finally { + currentTaskInDEV = previousTaskInDev; + } + } if (resumedBoundary.parentFlushed) { request.clientRenderedBoundaries.push(resumedBoundary); @@ -13006,8 +13081,7 @@ if (__DEV__) { nodes, slots, error, - errorDigest, - errorInfo + errorDigest ) { for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; @@ -13019,8 +13093,7 @@ if (__DEV__) { node[2], node[3], error, - errorDigest, - errorInfo + errorDigest ); } else { var boundaryNode = node; @@ -13029,8 +13102,7 @@ if (__DEV__) { request, rootSegmentID, error, - errorDigest, - errorInfo + errorDigest ); } } // Empty the set, since we've cleared it now. @@ -13047,7 +13119,11 @@ if (__DEV__) { ); } else if (boundary.status !== CLIENT_RENDERED) { boundary.status = CLIENT_RENDERED; - encodeErrorForBoundary(boundary, errorDigest, error, errorInfo); + boundary.errorDigest = errorDigest; + + { + captureBoundaryErrorDetailsDev(boundary, error); + } if (boundary.parentFlushed) { request.clientRenderedBoundaries.push(boundary); @@ -13073,15 +13149,13 @@ if (__DEV__) { } if (boundary === null) { - var errorInfo = {}; - if (request.status !== CLOSING && request.status !== CLOSED) { var replay = task.replay; if (replay === null) { // We didn't complete the root so we have nothing to show. We can close // the request; - logRecoverableError(request, error, errorInfo); + logRecoverableError(request, error); fatalError(request, error); return; } else { @@ -13091,15 +13165,14 @@ if (__DEV__) { replay.pendingTasks--; if (replay.pendingTasks === 0 && replay.nodes.length > 0) { - var errorDigest = logRecoverableError(request, error, errorInfo); + var errorDigest = logRecoverableError(request, error); abortRemainingReplayNodes( request, null, replay.nodes, replay.slots, error, - errorDigest, - errorInfo + errorDigest ); } @@ -13114,18 +13187,13 @@ if (__DEV__) { boundary.pendingTasks--; if (boundary.status !== CLIENT_RENDERED) { - boundary.status = CLIENT_RENDERED; // We construct an errorInfo from the boundary's componentStack so the error in dev will indicate which - // boundary the message is referring to - - var _errorInfo = getThrownInfo(task.componentStack); - - var _errorDigest = logRecoverableError(request, error, _errorInfo); - - var errorMessage = error; + boundary.status = CLIENT_RENDERED; + boundary.errorDigest = logRecoverableError(request, error); { var errorPrefix = "The server did not finish this Suspense boundary: "; + var errorMessage; if (error && typeof error.message === "string") { errorMessage = errorPrefix + error.message; @@ -13133,14 +13201,16 @@ if (__DEV__) { // eslint-disable-next-line react-internal/safe-string-coercion errorMessage = errorPrefix + String(error); } - } - encodeErrorForBoundary( - boundary, - _errorDigest, - errorMessage, - _errorInfo - ); + var previousTaskInDev = currentTaskInDEV; + currentTaskInDEV = task; + + try { + captureBoundaryErrorDetailsDev(boundary, errorMessage); + } finally { + currentTaskInDEV = previousTaskInDev; + } + } if (boundary.parentFlushed) { request.clientRenderedBoundaries.push(boundary); @@ -13170,8 +13240,7 @@ if (__DEV__) { ); } catch (error) { // We assume preloads are optimistic and thus non-fatal if errored. - var errorInfo = {}; - logRecoverableError(request, error, errorInfo); + logRecoverableError(request, error); } } // I extracted this function out because we want to ensure we consistently emit preloads before // transitioning to the next request stage and this transition can happen in multiple places in this @@ -13402,10 +13471,9 @@ if (__DEV__) { } } - var errorInfo = getThrownInfo(task.componentStack); task.abortSet.delete(task); segment.status = ERRORED; - erroredTask(request, task.blockedBoundary, x, errorInfo); + erroredTask(request, task.blockedBoundary, x); return; } finally { { @@ -13487,12 +13555,10 @@ if (__DEV__) { task.replay.pendingTasks--; task.abortSet.delete(task); - var errorInfo = getThrownInfo(task.componentStack); erroredReplay( request, task.blockedBoundary, x, - errorInfo, task.replay.nodes, task.replay.slots ); @@ -13565,8 +13631,7 @@ if (__DEV__) { flushCompletedQueues(request, request.destination); } } catch (error) { - var errorInfo = {}; - logRecoverableError(request, error, errorInfo); + logRecoverableError(request, error); fatalError(request, error); } finally { setCurrentResumableState(prevResumableState); @@ -14097,8 +14162,7 @@ if (__DEV__) { try { flushCompletedQueues(request, destination); } catch (error) { - var errorInfo = {}; - logRecoverableError(request, error, errorInfo); + logRecoverableError(request, error); fatalError(request, error); } } @@ -14127,8 +14191,7 @@ if (__DEV__) { flushCompletedQueues(request, request.destination); } } catch (error) { - var errorInfo = {}; - logRecoverableError(request, error, errorInfo); + logRecoverableError(request, error); fatalError(request, error); } } diff --git a/compiled/facebook-www/ReactDOMServer-dev.modern.js b/compiled/facebook-www/ReactDOMServer-dev.modern.js index 4585a23268420..29e66f828572d 100644 --- a/compiled/facebook-www/ReactDOMServer-dev.modern.js +++ b/compiled/facebook-www/ReactDOMServer-dev.modern.js @@ -19,7 +19,7 @@ if (__DEV__) { var React = require("react"); var ReactDOM = require("react-dom"); - var ReactVersion = "18.3.0-www-modern-50304adb"; + var ReactVersion = "18.3.0-www-modern-72a07bd7"; // This refers to a WWW module. var warningWWW = require("warning"); @@ -10572,8 +10572,7 @@ if (__DEV__) { rootFormatContext, emptyContextObject, rootContextSnapshot, - emptyTreeContext, - null + emptyTreeContext ); pingedTasks.push(rootTask); return request; @@ -10625,8 +10624,7 @@ if (__DEV__) { formatContext, legacyContext, context, - treeContext, - componentStack + treeContext ) { request.allPendingTasks++; @@ -10651,9 +10649,13 @@ if (__DEV__) { legacyContext: legacyContext, context: context, treeContext: treeContext, - componentStack: componentStack, thenableState: thenableState }; + + { + task.componentStack = null; + } + abortSet.add(task); return task; } @@ -10670,8 +10672,7 @@ if (__DEV__) { formatContext, legacyContext, context, - treeContext, - componentStack + treeContext ) { request.allPendingTasks++; @@ -10697,9 +10698,13 @@ if (__DEV__) { legacyContext: legacyContext, context: context, treeContext: treeContext, - componentStack: componentStack, thenableState: thenableState }; + + { + task.componentStack = null; + } + abortSet.add(task); return task; } @@ -10742,52 +10747,52 @@ if (__DEV__) { } } - function getStackFromNode(stackNode) { - return getStackByComponentStackNode(stackNode); - } - - function createBuiltInComponentStack(task, type) { - return { - tag: 0, - parent: task.componentStack, - type: type - }; + function pushBuiltInComponentStackInDEV(task, type) { + { + task.componentStack = { + tag: 0, + parent: task.componentStack, + type: type + }; + } } - function createFunctionComponentStack(task, type) { - return { - tag: 1, - parent: task.componentStack, - type: type - }; + function pushFunctionComponentStackInDEV(task, type) { + { + task.componentStack = { + tag: 1, + parent: task.componentStack, + type: type + }; + } } - function createClassComponentStack(task, type) { - return { - tag: 2, - parent: task.componentStack, - type: type - }; - } // While we track component stacks in prod all the time we only produce a reified stack in dev and - // during prerender in Prod. The reason for this is that the stack is useful for prerender where the timeliness - // of the request is less critical than the observability of the execution. For renders and resumes however we - // prioritize speed of the request. - - function getThrownInfo(node) { - if (node) { - return { - componentStack: getStackFromNode(node) + function pushClassComponentStackInDEV(task, type) { + { + task.componentStack = { + tag: 2, + parent: task.componentStack, + type: type }; - } else { - return {}; } } - function encodeErrorForBoundary(boundary, digest, error, thrownInfo) { - boundary.errorDigest = digest; + function popComponentStackInDEV(task) { + { + if (task.componentStack === null) { + error( + "Unexpectedly popped too many stack frames. This is a bug in React." + ); + } else { + task.componentStack = task.componentStack.parent; + } + } + } // stash the component stack of an unwinding error until it is processed + + var lastBoundaryErrorComponentStackDev = null; + function captureBoundaryErrorDetailsDev(boundary, error) { { - // In dev we additionally encode the error message and component stack on the boundary var errorMessage; if (typeof error === "string") { @@ -10799,27 +10804,26 @@ if (__DEV__) { errorMessage = String(error); } + var errorComponentStack = + lastBoundaryErrorComponentStackDev || getCurrentStackInDEV(); + lastBoundaryErrorComponentStackDev = null; boundary.errorMessage = errorMessage; - boundary.errorComponentStack = thrownInfo.componentStack; + boundary.errorComponentStack = errorComponentStack; } } - function logRecoverableError(request, error$1, errorInfo) { + function logRecoverableError(request, error) { // If this callback errors, we intentionally let that error bubble up to become a fatal error // so that someone fixes the error reporting instead of hiding it. - var errorDigest = request.onError(error$1, errorInfo); + var errorDigest = request.onError(error); if (errorDigest != null && typeof errorDigest !== "string") { - // We used to throw here but since this gets called from a variety of unprotected places it - // seems better to just warn and discard the returned value. - { - error( - 'onError returned something with a type other than "string". onError should return a string and may return null or undefined but must not return anything else. It received something of type "%s" instead', - typeof errorDigest - ); - } - - return; + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error( + 'onError returned something with a type other than "string". onError should return a string and may return null or undefined but must not return anything else. It received something of type "' + + typeof errorDigest + + '" instead' + ); } return errorDigest; @@ -10862,11 +10866,7 @@ if (__DEV__) { } // $FlowFixMe: Refined. var task = someTask; - var previousComponentStack = task.componentStack; // If we end up creating the fallback task we need it to have the correct stack which is - // the stack for the boundary itself. We stash it here so we can use it if needed later - - var suspenseComponentStack = (task.componentStack = - createBuiltInComponentStack(task, "Suspense")); + pushBuiltInComponentStackInDEV(task, "Suspense"); var prevKeyPath = task.keyPath; var parentBoundary = task.blockedBoundary; var parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for @@ -10940,25 +10940,27 @@ if (__DEV__) { queueCompletedSegment(newBoundary, contentRootSegment); if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) { - // This must have been the last segment we were waiting on. This boundary is now complete. + newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete. // Therefore we won't need the fallback. We early return so that we don't have to create // the fallback. - newBoundary.status = COMPLETED; // We are returning early so we need to restore the - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); return; } } catch (error) { contentRootSegment.status = ERRORED; newBoundary.status = CLIENT_RENDERED; - var thrownInfo = getThrownInfo(task.componentStack); var errorDigest; { - errorDigest = logRecoverableError(request, error, thrownInfo); + errorDigest = logRecoverableError(request, error); } - encodeErrorForBoundary(newBoundary, errorDigest, error, thrownInfo); // We don't need to decrement any task numbers because we didn't spawn any new task. + newBoundary.errorDigest = errorDigest; + + { + captureBoundaryErrorDetailsDev(newBoundary, error); + } // We don't need to decrement any task numbers because we didn't spawn any new task. // We don't need to schedule any task because we know the parent has written yet. // We do need to fallthrough to create the fallback though. } finally { @@ -10972,7 +10974,6 @@ if (__DEV__) { task.blockedBoundary = parentBoundary; task.blockedSegment = parentSegment; task.keyPath = prevKeyPath; - task.componentStack = previousComponentStack; } var fallbackKeyPath = [keyPath[0], "Suspense Fallback", keyPath[2]]; @@ -11012,13 +11013,16 @@ if (__DEV__) { task.formatContext, task.legacyContext, task.context, - task.treeContext, // This stack should be the Suspense boundary stack because while the fallback is actually a child segment - // of the parent boundary from a component standpoint the fallback is a child of the Suspense boundary itself - suspenseComponentStack - ); // TODO: This should be queued at a separate lower priority queue so that we only work + task.treeContext + ); + + { + suspendedFallbackTask.componentStack = task.componentStack; + } // TODO: This should be queued at a separate lower priority queue so that we only work // on preparing fallbacks if we don't have any more main content to task on. request.pingedTasks.push(suspendedFallbackTask); + popComponentStackInDEV(task); } function replaySuspenseBoundary( @@ -11032,11 +11036,7 @@ if (__DEV__) { fallbackNodes, fallbackSlots ) { - var previousComponentStack = task.componentStack; // If we end up creating the fallback task we need it to have the correct stack which is - // the stack for the boundary itself. We stash it here so we can use it if needed later - - var suspenseComponentStack = (task.componentStack = - createBuiltInComponentStack(task, "Suspense")); + pushBuiltInComponentStackInDEV(task, "Suspense"); var prevKeyPath = task.keyPath; var previousReplaySet = task.replay; var parentBoundary = task.blockedBoundary; @@ -11081,26 +11081,28 @@ if (__DEV__) { resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING ) { - // This must have been the last segment we were waiting on. This boundary is now complete. + resumedBoundary.status = COMPLETED; + request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete. // Therefore we won't need the fallback. We early return so that we don't have to create // the fallback. - resumedBoundary.status = COMPLETED; - request.completedBoundaries.push(resumedBoundary); // We restore the parent componentStack. Semantically this is the same as - // popComponentStack(task) but we do this instead because it should be slightly - // faster + popComponentStackInDEV(task); return; } } catch (error) { resumedBoundary.status = CLIENT_RENDERED; - var thrownInfo = getThrownInfo(task.componentStack); var errorDigest; { - errorDigest = logRecoverableError(request, error, thrownInfo); + errorDigest = logRecoverableError(request, error); + } + + resumedBoundary.errorDigest = errorDigest; + + { + captureBoundaryErrorDetailsDev(resumedBoundary, error); } - encodeErrorForBoundary(resumedBoundary, errorDigest, error, thrownInfo); task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted. request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task. @@ -11117,7 +11119,6 @@ if (__DEV__) { task.blockedBoundary = parentBoundary; task.replay = previousReplaySet; task.keyPath = prevKeyPath; - task.componentStack = previousComponentStack; } var fallbackKeyPath = [keyPath[0], "Suspense Fallback", keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work @@ -11140,18 +11141,20 @@ if (__DEV__) { task.formatContext, task.legacyContext, task.context, - task.treeContext, // This stack should be the Suspense boundary stack because while the fallback is actually a child segment - // of the parent boundary from a component standpoint the fallback is a child of the Suspense boundary itself - suspenseComponentStack - ); // TODO: This should be queued at a separate lower priority queue so that we only work + task.treeContext + ); + + { + suspendedFallbackTask.componentStack = task.componentStack; + } // TODO: This should be queued at a separate lower priority queue so that we only work // on preparing fallbacks if we don't have any more main content to task on. request.pingedTasks.push(suspendedFallbackTask); + popComponentStackInDEV(task); } function renderHostElement(request, task, keyPath, type, props) { - var previousComponentStack = task.componentStack; - task.componentStack = createBuiltInComponentStack(task, type); + pushBuiltInComponentStackInDEV(task, type); var segment = task.blockedSegment; if (segment === null) { @@ -11203,7 +11206,7 @@ if (__DEV__) { segment.lastPushedText = false; } - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); } function shouldConstruct(Component) { @@ -11262,13 +11265,12 @@ if (__DEV__) { } function renderClassComponent(request, task, keyPath, Component, props) { - var previousComponentStack = task.componentStack; - task.componentStack = createClassComponentStack(task, Component); + pushClassComponentStackInDEV(task, Component); var maskedContext = undefined; var instance = constructClassInstance(Component, props); mountClassInstance(instance, Component, props, maskedContext); finishClassComponent(request, task, keyPath, instance, Component, props); - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); } var didWarnAboutBadClass = {}; @@ -11292,8 +11294,7 @@ if (__DEV__) { ) { var legacyContext; - var previousComponentStack = task.componentStack; - task.componentStack = createFunctionComponentStack(task, Component); + pushFunctionComponentStackInDEV(task, Component); { if ( @@ -11383,7 +11384,7 @@ if (__DEV__) { ); } - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); } function finishFunctionComponent( @@ -11541,8 +11542,7 @@ if (__DEV__) { props, ref ) { - var previousComponentStack = task.componentStack; - task.componentStack = createFunctionComponentStack(task, type.render); + pushFunctionComponentStackInDEV(task, type.render); var children = renderWithHooks( request, task, @@ -11564,7 +11564,7 @@ if (__DEV__) { formStateCount, formStateMatchingIndex ); - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); } function renderMemo( @@ -11673,8 +11673,7 @@ if (__DEV__) { props, ref ) { - var previousComponentStack = task.componentStack; - task.componentStack = createBuiltInComponentStack(task, "Lazy"); + pushBuiltInComponentStackInDEV(task, "Lazy"); var payload = lazyComponent._payload; var init = lazyComponent._init; var Component = init(payload); @@ -11688,7 +11687,7 @@ if (__DEV__) { resolvedProps, ref ); - task.componentStack = previousComponentStack; + popComponentStackInDEV(task); } function renderOffscreen(request, task, keyPath, props) { @@ -11764,17 +11763,13 @@ if (__DEV__) { } case REACT_SUSPENSE_LIST_TYPE: { - var preiousComponentStack = task.componentStack; - task.componentStack = createBuiltInComponentStack( - task, - "SuspenseList" - ); // TODO: SuspenseList should control the boundaries. + pushBuiltInComponentStackInDEV(task, "SuspenseList"); // TODO: SuspenseList should control the boundaries. var _prevKeyPath3 = task.keyPath; task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); task.keyPath = _prevKeyPath3; - task.componentStack = preiousComponentStack; + popComponentStackInDEV(task); return; } @@ -12000,12 +11995,10 @@ if (__DEV__) { // replay nodes which might be Suspense boundaries which are able to // absorb the error and we can still continue with siblings. - var thrownInfo = getThrownInfo(task.componentStack); erroredReplay( request, task.blockedBoundary, x, - thrownInfo, childNodes, childSlots ); @@ -12078,8 +12071,7 @@ if (__DEV__) { didWarnAboutMaps = true; } } - } // This function by it self renders a node and consumes the task by mutating it - // to update the current execution state. + } function renderNodeDestructive( request, @@ -12088,6 +12080,45 @@ if (__DEV__) { prevThenableState, node, childIndex + ) { + { + // In Dev we wrap renderNodeDestructiveImpl in a try / catch so we can capture + // a component stack at the right place in the tree. We don't do this in renderNode + // becuase it is not called at every layer of the tree and we may lose frames + try { + return renderNodeDestructiveImpl( + request, + task, + prevThenableState, + node, + childIndex + ); + } catch (x) { + if ( + typeof x === "object" && + x !== null && + typeof x.then === "function" + ); + else { + // This is an error, stash the component stack if it is null. + lastBoundaryErrorComponentStackDev = + lastBoundaryErrorComponentStackDev !== null + ? lastBoundaryErrorComponentStackDev + : getCurrentStackInDEV(); + } // rethrow so normal suspense logic can handle thrown value accordingly + + throw x; + } + } + } // This function by it self renders a node and consumes the task by mutating it + // to update the current execution state. + + function renderNodeDestructiveImpl( + request, + task, + prevThenableState, + node, + childIndex ) { if (task.replay !== null && typeof task.replay.slots === "number") { // TODO: Figure out a cheaper place than this hot path to do this check. @@ -12151,15 +12182,30 @@ if (__DEV__) { ); case REACT_LAZY_TYPE: { - var previousComponentStack = task.componentStack; - task.componentStack = createBuiltInComponentStack(task, "Lazy"); var lazyNode = node; var payload = lazyNode._payload; var init = lazyNode._init; - var resolvedNode = init(payload); // We restore the stack before rendering the resolved node because once the Lazy - // has resolved any future errors + var resolvedNode; - task.componentStack = previousComponentStack; // Now we render the resolved node + { + try { + resolvedNode = init(payload); + } catch (x) { + if ( + typeof x === "object" && + x !== null && + typeof x.then === "function" + ) { + // this Lazy initializer is suspending. push a temporary frame onto the stack so it can be + // popped off in spawnNewSuspendedTask. This aligns stack behavior between Lazy in element position + // vs Component position. We do not want the frame for Errors so we exclusively do this in + // the wakeable branch + pushBuiltInComponentStackInDEV(task, "Lazy"); + } + + throw x; + } + } renderNodeDestructive( request, @@ -12222,7 +12268,7 @@ if (__DEV__) { if (typeof maybeUsable.then === "function") { var thenable = maybeUsable; - return renderNodeDestructive( + return renderNodeDestructiveImpl( request, task, null, @@ -12236,7 +12282,7 @@ if (__DEV__) { maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE ) { var context = maybeUsable; - return renderNodeDestructive( + return renderNodeDestructiveImpl( request, task, null, @@ -12349,12 +12395,10 @@ if (__DEV__) { // absorb the error and we can still continue with siblings. // This is an error, stash the component stack if it is null. - var thrownInfo = getThrownInfo(task.componentStack); erroredReplay( request, task.blockedBoundary, x, - thrownInfo, childNodes, childSlots ); @@ -12448,10 +12492,17 @@ if (__DEV__) { task.formatContext, task.legacyContext, task.context, - task.treeContext, // We pop one task off the stack because the node that suspended will be tried again, - // which will add it back onto the stack. - task.componentStack !== null ? task.componentStack.parent : null + task.treeContext ); + + { + if (task.componentStack !== null) { + // We pop one task off the stack because the node that suspended will be tried again, + // which will add it back onto the stack. + newTask.componentStack = task.componentStack.parent; + } + } + var ping = newTask.ping; x.then(ping, ping); } @@ -12483,10 +12534,17 @@ if (__DEV__) { task.formatContext, task.legacyContext, task.context, - task.treeContext, // We pop one task off the stack because the node that suspended will be tried again, - // which will add it back onto the stack. - task.componentStack !== null ? task.componentStack.parent : null + task.treeContext ); + + { + if (task.componentStack !== null) { + // We pop one task off the stack because the node that suspended will be tried again, + // which will add it back onto the stack. + newTask.componentStack = task.componentStack.parent; + } + } + var ping = newTask.ping; x.then(ping, ping); } // This is a non-destructive form of rendering a node. If it suspends it spawns @@ -12500,7 +12558,12 @@ if (__DEV__) { var previousContext = task.context; var previousKeyPath = task.keyPath; var previousTreeContext = task.treeContext; - var previousComponentStack = task.componentStack; + var previousComponentStack = null; + + { + previousComponentStack = task.componentStack; + } + var x; // Store how much we've pushed at this point so we can reset it in case something // suspended partially through writing something. @@ -12538,10 +12601,14 @@ if (__DEV__) { task.legacyContext = previousLegacyContext; task.context = previousContext; task.keyPath = previousKeyPath; - task.treeContext = previousTreeContext; - task.componentStack = previousComponentStack; // Restore all active ReactContexts to what they were before. + task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before. switchContext(previousContext); + + { + task.componentStack = previousComponentStack; + } + return; } } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode. @@ -12586,10 +12653,14 @@ if (__DEV__) { task.legacyContext = previousLegacyContext; task.context = previousContext; task.keyPath = previousKeyPath; - task.treeContext = previousTreeContext; - task.componentStack = previousComponentStack; // Restore all active ReactContexts to what they were before. + task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before. switchContext(previousContext); + + { + task.componentStack = previousComponentStack; + } + return; } } @@ -12601,23 +12672,19 @@ if (__DEV__) { task.legacyContext = previousLegacyContext; task.context = previousContext; task.keyPath = previousKeyPath; - task.treeContext = previousTreeContext; // We intentionally do not restore the component stack on the error pathway - // Whatever handles the error needs to use this stack which is the location of the - // error. We must restore the stack wherever we handle this - // Restore all active ReactContexts to what they were before. + task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before. switchContext(previousContext); + + { + task.componentStack = previousComponentStack; + } // We assume that we don't need the correct context. + // Let's terminate the rest of the tree and don't render any siblings. + throw x; } - function erroredReplay( - request, - boundary, - error, - errorInfo, - replayNodes, - resumeSlots - ) { + function erroredReplay(request, boundary, error, replayNodes, resumeSlots) { // Erroring during a replay doesn't actually cause an error by itself because // that component has already rendered. What causes the error is the resumable // points that we did not yet finish which will be below the point of the reset. @@ -12628,7 +12695,7 @@ if (__DEV__) { var errorDigest; { - errorDigest = logRecoverableError(request, error, errorInfo); + errorDigest = logRecoverableError(request, error); } abortRemainingReplayNodes( @@ -12637,27 +12704,31 @@ if (__DEV__) { replayNodes, resumeSlots, error, - errorDigest, - errorInfo + errorDigest ); } - function erroredTask(request, boundary, error, errorInfo) { + function erroredTask(request, boundary, error) { // Report the error to a global handler. var errorDigest; { - errorDigest = logRecoverableError(request, error, errorInfo); + errorDigest = logRecoverableError(request, error); } if (boundary === null) { + lastBoundaryErrorComponentStackDev = null; fatalError(request, error); } else { boundary.pendingTasks--; if (boundary.status !== CLIENT_RENDERED) { boundary.status = CLIENT_RENDERED; - encodeErrorForBoundary(boundary, errorDigest, error, errorInfo); // Regardless of what happens next, this boundary won't be displayed, + boundary.errorDigest = errorDigest; + + { + captureBoundaryErrorDetailsDev(boundary, error); + } // Regardless of what happens next, this boundary won't be displayed, // so we can flush it, if the parent already flushed. if (boundary.parentFlushed) { @@ -12667,6 +12738,8 @@ if (__DEV__) { // We reuse the same queue for errors. request.clientRenderedBoundaries.push(boundary); } + } else { + lastBoundaryErrorComponentStackDev = null; } } @@ -12695,18 +12768,18 @@ if (__DEV__) { request, rootSegmentID, error, - errorDigest, - errorInfo + errorDigest ) { var resumedBoundary = createSuspenseBoundary(request, new Set()); resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender. resumedBoundary.rootSegmentID = rootSegmentID; resumedBoundary.status = CLIENT_RENDERED; - var errorMessage = error; + resumedBoundary.errorDigest = errorDigest; { var errorPrefix = "The server did not finish this Suspense boundary: "; + var errorMessage; if (error && typeof error.message === "string") { errorMessage = errorPrefix + error.message; @@ -12714,14 +12787,16 @@ if (__DEV__) { // eslint-disable-next-line react-internal/safe-string-coercion errorMessage = errorPrefix + String(error); } - } - encodeErrorForBoundary( - resumedBoundary, - errorDigest, - errorMessage, - errorInfo - ); + var previousTaskInDev = currentTaskInDEV; + currentTaskInDEV = null; + + try { + captureBoundaryErrorDetailsDev(resumedBoundary, errorMessage); + } finally { + currentTaskInDEV = previousTaskInDev; + } + } if (resumedBoundary.parentFlushed) { request.clientRenderedBoundaries.push(resumedBoundary); @@ -12734,8 +12809,7 @@ if (__DEV__) { nodes, slots, error, - errorDigest, - errorInfo + errorDigest ) { for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; @@ -12747,8 +12821,7 @@ if (__DEV__) { node[2], node[3], error, - errorDigest, - errorInfo + errorDigest ); } else { var boundaryNode = node; @@ -12757,8 +12830,7 @@ if (__DEV__) { request, rootSegmentID, error, - errorDigest, - errorInfo + errorDigest ); } } // Empty the set, since we've cleared it now. @@ -12775,7 +12847,11 @@ if (__DEV__) { ); } else if (boundary.status !== CLIENT_RENDERED) { boundary.status = CLIENT_RENDERED; - encodeErrorForBoundary(boundary, errorDigest, error, errorInfo); + boundary.errorDigest = errorDigest; + + { + captureBoundaryErrorDetailsDev(boundary, error); + } if (boundary.parentFlushed) { request.clientRenderedBoundaries.push(boundary); @@ -12801,15 +12877,13 @@ if (__DEV__) { } if (boundary === null) { - var errorInfo = {}; - if (request.status !== CLOSING && request.status !== CLOSED) { var replay = task.replay; if (replay === null) { // We didn't complete the root so we have nothing to show. We can close // the request; - logRecoverableError(request, error, errorInfo); + logRecoverableError(request, error); fatalError(request, error); return; } else { @@ -12819,15 +12893,14 @@ if (__DEV__) { replay.pendingTasks--; if (replay.pendingTasks === 0 && replay.nodes.length > 0) { - var errorDigest = logRecoverableError(request, error, errorInfo); + var errorDigest = logRecoverableError(request, error); abortRemainingReplayNodes( request, null, replay.nodes, replay.slots, error, - errorDigest, - errorInfo + errorDigest ); } @@ -12842,18 +12915,13 @@ if (__DEV__) { boundary.pendingTasks--; if (boundary.status !== CLIENT_RENDERED) { - boundary.status = CLIENT_RENDERED; // We construct an errorInfo from the boundary's componentStack so the error in dev will indicate which - // boundary the message is referring to - - var _errorInfo = getThrownInfo(task.componentStack); - - var _errorDigest = logRecoverableError(request, error, _errorInfo); - - var errorMessage = error; + boundary.status = CLIENT_RENDERED; + boundary.errorDigest = logRecoverableError(request, error); { var errorPrefix = "The server did not finish this Suspense boundary: "; + var errorMessage; if (error && typeof error.message === "string") { errorMessage = errorPrefix + error.message; @@ -12861,14 +12929,16 @@ if (__DEV__) { // eslint-disable-next-line react-internal/safe-string-coercion errorMessage = errorPrefix + String(error); } - } - encodeErrorForBoundary( - boundary, - _errorDigest, - errorMessage, - _errorInfo - ); + var previousTaskInDev = currentTaskInDEV; + currentTaskInDEV = task; + + try { + captureBoundaryErrorDetailsDev(boundary, errorMessage); + } finally { + currentTaskInDEV = previousTaskInDev; + } + } if (boundary.parentFlushed) { request.clientRenderedBoundaries.push(boundary); @@ -12898,8 +12968,7 @@ if (__DEV__) { ); } catch (error) { // We assume preloads are optimistic and thus non-fatal if errored. - var errorInfo = {}; - logRecoverableError(request, error, errorInfo); + logRecoverableError(request, error); } } // I extracted this function out because we want to ensure we consistently emit preloads before // transitioning to the next request stage and this transition can happen in multiple places in this @@ -13130,10 +13199,9 @@ if (__DEV__) { } } - var errorInfo = getThrownInfo(task.componentStack); task.abortSet.delete(task); segment.status = ERRORED; - erroredTask(request, task.blockedBoundary, x, errorInfo); + erroredTask(request, task.blockedBoundary, x); return; } finally { { @@ -13215,12 +13283,10 @@ if (__DEV__) { task.replay.pendingTasks--; task.abortSet.delete(task); - var errorInfo = getThrownInfo(task.componentStack); erroredReplay( request, task.blockedBoundary, x, - errorInfo, task.replay.nodes, task.replay.slots ); @@ -13293,8 +13359,7 @@ if (__DEV__) { flushCompletedQueues(request, request.destination); } } catch (error) { - var errorInfo = {}; - logRecoverableError(request, error, errorInfo); + logRecoverableError(request, error); fatalError(request, error); } finally { setCurrentResumableState(prevResumableState); @@ -13825,8 +13890,7 @@ if (__DEV__) { try { flushCompletedQueues(request, destination); } catch (error) { - var errorInfo = {}; - logRecoverableError(request, error, errorInfo); + logRecoverableError(request, error); fatalError(request, error); } } @@ -13855,8 +13919,7 @@ if (__DEV__) { flushCompletedQueues(request, request.destination); } } catch (error) { - var errorInfo = {}; - logRecoverableError(request, error, errorInfo); + logRecoverableError(request, error); fatalError(request, error); } } diff --git a/compiled/facebook-www/ReactDOMServer-prod.classic.js b/compiled/facebook-www/ReactDOMServer-prod.classic.js index f829a34cf3424..a8567e68b1f26 100644 --- a/compiled/facebook-www/ReactDOMServer-prod.classic.js +++ b/compiled/facebook-www/ReactDOMServer-prod.classic.js @@ -591,8 +591,8 @@ function pushAttribute(target, name, value) { case "symbol": return; case "boolean": - var prefix$7 = name.toLowerCase().slice(0, 5); - if ("data-" !== prefix$7 && "aria-" !== prefix$7) return; + var prefix = name.toLowerCase().slice(0, 5); + if ("data-" !== prefix && "aria-" !== prefix) return; } target.push(" ", name, '="', escapeTextForBrowser(value), '"'); } @@ -2483,16 +2483,16 @@ function createRenderState(resumableState, generateStaticMarkup) { "\x3c/script>" ); bootstrapScriptContent = idPrefix + "P:"; - var JSCompiler_object_inline_segmentPrefix_1672 = idPrefix + "S:"; + var JSCompiler_object_inline_segmentPrefix_1602 = idPrefix + "S:"; idPrefix += "B:"; - var JSCompiler_object_inline_preconnects_1687 = new Set(), - JSCompiler_object_inline_fontPreloads_1688 = new Set(), - JSCompiler_object_inline_highImagePreloads_1689 = new Set(), - JSCompiler_object_inline_styles_1690 = new Map(), - JSCompiler_object_inline_bootstrapScripts_1691 = new Set(), - JSCompiler_object_inline_scripts_1692 = new Set(), - JSCompiler_object_inline_bulkPreloads_1693 = new Set(), - JSCompiler_object_inline_preloads_1694 = { + var JSCompiler_object_inline_preconnects_1617 = new Set(), + JSCompiler_object_inline_fontPreloads_1618 = new Set(), + JSCompiler_object_inline_highImagePreloads_1619 = new Set(), + JSCompiler_object_inline_styles_1620 = new Map(), + JSCompiler_object_inline_bootstrapScripts_1621 = new Set(), + JSCompiler_object_inline_scripts_1622 = new Set(), + JSCompiler_object_inline_bulkPreloads_1623 = new Set(), + JSCompiler_object_inline_preloads_1624 = { images: new Map(), stylesheets: new Map(), scripts: new Map(), @@ -2529,7 +2529,7 @@ function createRenderState(resumableState, generateStaticMarkup) { scriptConfig.moduleScriptResources[href] = null; scriptConfig = []; pushLinkImpl(scriptConfig, props); - JSCompiler_object_inline_bootstrapScripts_1691.add(scriptConfig); + JSCompiler_object_inline_bootstrapScripts_1621.add(scriptConfig); bootstrapChunks.push('