mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 00:20:04 +01:00
[DevTools] Use source maps to infer name asynchronously (#34212)
This commit is contained in:
parent
a85ec041d6
commit
11d7bcf88c
|
|
@ -20,6 +20,7 @@ import {withPermissionsCheck} from 'react-devtools-shared/src/frontend/utils/wit
|
|||
import StackTraceView from './StackTraceView';
|
||||
import OwnerView from './OwnerView';
|
||||
import {meta} from '../../../hydration';
|
||||
import useInferredName from '../useInferredName';
|
||||
|
||||
import type {
|
||||
InspectedElement,
|
||||
|
|
@ -101,21 +102,7 @@ function SuspendedByRow({
|
|||
}: RowProps) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const ioInfo = asyncInfo.awaited;
|
||||
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 name = useInferredName(asyncInfo);
|
||||
const description = ioInfo.description;
|
||||
const longName = description === '' ? name : name + ' (' + description + ')';
|
||||
const shortDescription = getShortDescription(name, description);
|
||||
|
|
|
|||
78
packages/react-devtools-shared/src/devtools/views/useInferredName.js
vendored
Normal file
78
packages/react-devtools-shared/src/devtools/views/useInferredName.js
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
import {use, useContext, useDeferredValue} from 'react';
|
||||
|
||||
import type {ReactCallSite} from 'shared/ReactTypes';
|
||||
|
||||
import type {SourceMappedLocation} from 'react-devtools-shared/src/symbolicateSource';
|
||||
|
||||
import type {SerializedAsyncInfo} from 'react-devtools-shared/src/frontend/types';
|
||||
|
||||
import FetchFileWithCachingContext from './Components/FetchFileWithCachingContext';
|
||||
|
||||
import {symbolicateSourceWithCache} from 'react-devtools-shared/src/symbolicateSource';
|
||||
|
||||
export default function useInferredName(
|
||||
asyncInfo: SerializedAsyncInfo,
|
||||
): string {
|
||||
const fetchFileWithCaching = useContext(FetchFileWithCachingContext);
|
||||
const name = asyncInfo.awaited.name;
|
||||
let inferNameFromStack = null;
|
||||
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 = asyncInfo.awaited.stack || asyncInfo.stack;
|
||||
if (bestStack !== null && bestStack.length > 1) {
|
||||
inferNameFromStack = bestStack;
|
||||
}
|
||||
}
|
||||
// Start by not source mapping and just taking the first name and upgrade to
|
||||
// the better name asynchronously if we find one. Most of the time it'll just be
|
||||
// the top of the stack.
|
||||
const shouldSourceMap = useDeferredValue(inferNameFromStack !== null, false);
|
||||
if (inferNameFromStack !== null) {
|
||||
if (shouldSourceMap) {
|
||||
let bestMatch = '';
|
||||
for (let i = 0; i < inferNameFromStack.length; i++) {
|
||||
const callSite: ReactCallSite = inferNameFromStack[i];
|
||||
const [virtualFunctionName, virtualURL, virtualLine, virtualColumn] =
|
||||
callSite;
|
||||
const symbolicatedCallSite: null | SourceMappedLocation =
|
||||
fetchFileWithCaching !== null
|
||||
? use(
|
||||
symbolicateSourceWithCache(
|
||||
fetchFileWithCaching,
|
||||
virtualURL,
|
||||
virtualLine,
|
||||
virtualColumn,
|
||||
),
|
||||
)
|
||||
: null;
|
||||
if (symbolicatedCallSite === null) {
|
||||
// If we can't source map, we treat it as first party code. We called whatever was
|
||||
// the previous callsite.
|
||||
if (bestMatch === '') {
|
||||
return virtualFunctionName || name;
|
||||
} else {
|
||||
return bestMatch;
|
||||
}
|
||||
} else if (!symbolicatedCallSite.ignored) {
|
||||
if (bestMatch === '') {
|
||||
// If we had no good stack frames for internal calls, just use the last
|
||||
// first party function name.
|
||||
return symbolicatedCallSite[0] || virtualFunctionName || name;
|
||||
} else {
|
||||
return bestMatch;
|
||||
}
|
||||
} else {
|
||||
// This line was ignore listed, it might be the one we called into from first party.
|
||||
bestMatch = symbolicatedCallSite[0] || virtualFunctionName;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
} else {
|
||||
return inferNameFromStack[0][0];
|
||||
}
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user