react/packages/shared/ReactComponentInfoStack.js
Sebastian Markbåge 12e9579099
[Flight] Enable owner stacks on the client when replaying logs (#30473)
There's a special case that happens when we replay logs on the client
because this doesn't happen within the context of any particular
rendered component. So we need to reimplement things that would normally
be handled by a full client like Fiber.

The implementation of `getOwnerStackByComponentInfoInDev` is the
simplest version since it doesn't have any client components in it so I
move it to `shared/`. It's only used by Flight but both `react-server/`
and `react-client/` packages. The ReactComponentInfo type is also more
generic than just Flight anyway.

In a follow up I still need to implement this in React DevTools when
native tasks are not available so that it appends it to the console.
2024-07-31 07:56:15 -04:00

56 lines
1.7 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type {ReactComponentInfo} from 'shared/ReactTypes';
import {describeBuiltInComponentFrame} from 'shared/ReactComponentStackFrame';
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import {formatOwnerStack} from 'shared/ReactOwnerStackFrames';
export function getOwnerStackByComponentInfoInDev(
componentInfo: ReactComponentInfo,
): string {
if (!enableOwnerStacks || !__DEV__) {
return '';
}
try {
let info = '';
// The owner stack of the current component will be where it was created, i.e. inside its owner.
// There's no actual name of the currently executing component. Instead, that is available
// on the regular stack that's currently executing. However, if there is no owner at all, then
// there's no stack frame so we add the name of the root component to the stack to know which
// component is currently executing.
if (!componentInfo.owner && typeof componentInfo.name === 'string') {
return describeBuiltInComponentFrame(componentInfo.name);
}
let owner: void | null | ReactComponentInfo = componentInfo;
while (owner) {
const ownerStack: ?Error = owner.debugStack;
if (ownerStack != null) {
// Server Component
owner = owner.owner;
if (owner) {
// TODO: Should we stash this somewhere for caching purposes?
info += '\n' + formatOwnerStack(ownerStack);
}
} else {
break;
}
}
return info;
} catch (x) {
return '\nError generating stack: ' + x.message + '\n' + x.stack;
}
}