[DevTools] If the await doesn't have a stack use the stack from use() if any (#34162)

Stacked on #34148.

This picks up the stack for the await from the `use()` Hook if one was
used to get this async info.

When you select a component that used hooks, we already collect this
information.

If you select a Suspense boundary, this lazily invokes the first
component that awaited this data to inspects its hooks and produce a
stack trace for the use().

When all we have for the name is "Promise" I also use the name of the
first callsite in the stack trace if there's more than one. Which in
practice will be the name of the custom Hook that called it. Ideally
we'd use source mapping and ignore listing for this but that would
require suspending the display. We could maybe make the SuspendedByRow
wrapped in a Suspense boundary for this case.

<img width="438" height="401" alt="Screenshot 2025-08-10 at 10 07 55 PM"
src="https://github.com/user-attachments/assets/2a68917d-c27b-4c00-84aa-0ceb51c4e541"
/>
This commit is contained in:
Sebastian Markbåge
2025-08-11 12:28:10 -04:00
committed by GitHub
parent f1e70b5e0a
commit 2c9a42dfd7
2 changed files with 146 additions and 32 deletions

View File

@@ -81,7 +81,21 @@ function SuspendedByRow({
}: RowProps) {
const [isOpen, setIsOpen] = useState(false);
const ioInfo = asyncInfo.awaited;
const name = ioInfo.name;
let name = ioInfo.name;
if (name === '' || name === 'Promise') {
// If all we have is a generic name, we can try to infer a better name from
// the stack. We only do this if the stack has more than one frame since
// otherwise it's likely to just be the name of the component which isn't better.
const bestStack = ioInfo.stack || asyncInfo.stack;
if (bestStack !== null && bestStack.length > 1) {
// TODO: Ideally we'd get the name from the last ignore listed frame before the
// first visible frame since this is the same algorithm as the Flight server uses.
// Ideally, we'd also get the name from the source mapped entry instead of the
// original entry. However, that would require suspending the immediate display
// of these rows to first do source mapping before we can show the name.
name = bestStack[0][0];
}
}
const description = ioInfo.description;
const longName = description === '' ? name : name + ' (' + description + ')';
const shortDescription = getShortDescription(name, description);