mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
Get Server Component Function Location for Parent Stacks using Child's Owner Stack (#33629)
This is using the same trick as #30798 but for runtime code too. It's essential zero cost. This lets us include a source location for parent stacks of Server Components when it has an owned child's location. Either from JSX or I/O. Ironically, a Component that throws an error will likely itself not get the stack because it won't have any JSX rendered yet.
This commit is contained in:
parent
94cf60bede
commit
4a523489b7
10
packages/react-client/src/ReactFlightClient.js
vendored
10
packages/react-client/src/ReactFlightClient.js
vendored
|
|
@ -2739,9 +2739,15 @@ function initializeFakeStack(
|
||||||
// $FlowFixMe[cannot-write]
|
// $FlowFixMe[cannot-write]
|
||||||
debugInfo.debugStack = createFakeJSXCallStackInDEV(response, stack, env);
|
debugInfo.debugStack = createFakeJSXCallStackInDEV(response, stack, env);
|
||||||
}
|
}
|
||||||
if (debugInfo.owner != null) {
|
const owner = debugInfo.owner;
|
||||||
|
if (owner != null) {
|
||||||
// Initialize any owners not yet initialized.
|
// Initialize any owners not yet initialized.
|
||||||
initializeFakeStack(response, debugInfo.owner);
|
initializeFakeStack(response, owner);
|
||||||
|
if (owner.debugLocation === undefined && debugInfo.debugStack != null) {
|
||||||
|
// If we are the child of this owner, then the owner should be the bottom frame
|
||||||
|
// our stack. We can use it as the implied location of the owner.
|
||||||
|
owner.debugLocation = debugInfo.debugStack;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ function getErrorForJestMatcher(error) {
|
||||||
|
|
||||||
function normalizeComponentInfo(debugInfo) {
|
function normalizeComponentInfo(debugInfo) {
|
||||||
if (Array.isArray(debugInfo.stack)) {
|
if (Array.isArray(debugInfo.stack)) {
|
||||||
const {debugTask, debugStack, ...copy} = debugInfo;
|
const {debugTask, debugStack, debugLocation, ...copy} = debugInfo;
|
||||||
copy.stack = formatV8Stack(debugInfo.stack);
|
copy.stack = formatV8Stack(debugInfo.stack);
|
||||||
if (debugInfo.owner) {
|
if (debugInfo.owner) {
|
||||||
copy.owner = normalizeComponentInfo(debugInfo.owner);
|
copy.owner = normalizeComponentInfo(debugInfo.owner);
|
||||||
|
|
|
||||||
|
|
@ -5831,13 +5831,21 @@ export function attach(
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSourceForInstance(instance: DevToolsInstance): Source | null {
|
function getSourceForInstance(instance: DevToolsInstance): Source | null {
|
||||||
const unresolvedSource = instance.source;
|
let unresolvedSource = instance.source;
|
||||||
if (unresolvedSource === null) {
|
if (unresolvedSource === null) {
|
||||||
// We don't have any source yet. We can try again later in case an owned child mounts later.
|
// We don't have any source yet. We can try again later in case an owned child mounts later.
|
||||||
// TODO: We won't have any information here if the child is filtered.
|
// TODO: We won't have any information here if the child is filtered.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instance.kind === VIRTUAL_INSTANCE) {
|
||||||
|
// We might have found one on the virtual instance.
|
||||||
|
const debugLocation = instance.data.debugLocation;
|
||||||
|
if (debugLocation != null) {
|
||||||
|
unresolvedSource = debugLocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we have the debug stack (the creation stack of the JSX) for any owned child of this
|
// If we have the debug stack (the creation stack of the JSX) for any owned child of this
|
||||||
// component, then at the bottom of that stack will be a stack frame that is somewhere within
|
// component, then at the bottom of that stack will be a stack frame that is somewhere within
|
||||||
// the component's function body. Typically it would be the callsite of the JSX unless there's
|
// the component's function body. Typically it would be the callsite of the JSX unless there's
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,11 @@ export function getStackByFiberInDevAndProd(workInProgress: Fiber): string {
|
||||||
for (let i = debugInfo.length - 1; i >= 0; i--) {
|
for (let i = debugInfo.length - 1; i >= 0; i--) {
|
||||||
const entry = debugInfo[i];
|
const entry = debugInfo[i];
|
||||||
if (typeof entry.name === 'string') {
|
if (typeof entry.name === 'string') {
|
||||||
info += describeDebugInfoFrame(entry.name, entry.env);
|
info += describeDebugInfoFrame(
|
||||||
|
entry.name,
|
||||||
|
entry.env,
|
||||||
|
entry.debugLocation,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ function describeComponentStackByType(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof type.name === 'string') {
|
if (typeof type.name === 'string') {
|
||||||
return describeDebugInfoFrame(type.name, type.env);
|
return describeDebugInfoFrame(type.name, type.env, type.debugLocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ function normalizeStack(stack) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeIOInfo(ioInfo) {
|
function normalizeIOInfo(ioInfo) {
|
||||||
const {debugTask, debugStack, ...copy} = ioInfo;
|
const {debugTask, debugStack, debugLocation, ...copy} = ioInfo;
|
||||||
if (ioInfo.stack) {
|
if (ioInfo.stack) {
|
||||||
copy.stack = normalizeStack(ioInfo.stack);
|
copy.stack = normalizeStack(ioInfo.stack);
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +72,7 @@ function normalizeIOInfo(ioInfo) {
|
||||||
|
|
||||||
function normalizeDebugInfo(debugInfo) {
|
function normalizeDebugInfo(debugInfo) {
|
||||||
if (Array.isArray(debugInfo.stack)) {
|
if (Array.isArray(debugInfo.stack)) {
|
||||||
const {debugTask, debugStack, ...copy} = debugInfo;
|
const {debugTask, debugStack, debugLocation, ...copy} = debugInfo;
|
||||||
copy.stack = normalizeStack(debugInfo.stack);
|
copy.stack = normalizeStack(debugInfo.stack);
|
||||||
if (debugInfo.owner) {
|
if (debugInfo.owner) {
|
||||||
copy.owner = normalizeDebugInfo(debugInfo.owner);
|
copy.owner = normalizeDebugInfo(debugInfo.owner);
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
|
||||||
|
|
||||||
import DefaultPrepareStackTrace from 'shared/DefaultPrepareStackTrace';
|
import DefaultPrepareStackTrace from 'shared/DefaultPrepareStackTrace';
|
||||||
|
|
||||||
|
import {formatOwnerStack} from './ReactOwnerStackFrames';
|
||||||
|
|
||||||
let prefix;
|
let prefix;
|
||||||
let suffix;
|
let suffix;
|
||||||
export function describeBuiltInComponentFrame(name: string): string {
|
export function describeBuiltInComponentFrame(name: string): string {
|
||||||
|
|
@ -38,7 +40,24 @@ export function describeBuiltInComponentFrame(name: string): string {
|
||||||
return '\n' + prefix + name + suffix;
|
return '\n' + prefix + name + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function describeDebugInfoFrame(name: string, env: ?string): string {
|
export function describeDebugInfoFrame(
|
||||||
|
name: string,
|
||||||
|
env: ?string,
|
||||||
|
location: ?Error,
|
||||||
|
): string {
|
||||||
|
if (location != null) {
|
||||||
|
// If we have a location, it's the child's owner stack. Treat the bottom most frame as
|
||||||
|
// the location of this function.
|
||||||
|
const childStack = formatOwnerStack(location);
|
||||||
|
const idx = childStack.lastIndexOf('\n');
|
||||||
|
const lastLine = idx === -1 ? childStack : childStack.slice(idx + 1);
|
||||||
|
if (lastLine.indexOf(name) !== -1) {
|
||||||
|
// For async stacks it's possible we don't have the owner on it. As a precaution only
|
||||||
|
// use this frame if it has the name of the function in it.
|
||||||
|
return '\n' + lastLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return describeBuiltInComponentFrame(name + (env ? ' [' + env + ']' : ''));
|
return describeBuiltInComponentFrame(name + (env ? ' [' + env + ']' : ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,7 @@ export type ReactComponentInfo = {
|
||||||
// Stashed Data for the Specific Execution Environment. Not part of the transport protocol
|
// Stashed Data for the Specific Execution Environment. Not part of the transport protocol
|
||||||
+debugStack?: null | Error,
|
+debugStack?: null | Error,
|
||||||
+debugTask?: null | ConsoleTask,
|
+debugTask?: null | ConsoleTask,
|
||||||
|
debugLocation?: null | Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ReactEnvironmentInfo = {
|
export type ReactEnvironmentInfo = {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user