mirror of
https://github.com/facebook/react.git
synced 2026-02-23 20:23:02 +00:00
Track Owner for Server Components in DEV (#28753)
This implements the concept of a DEV-only "owner" for Server Components. The owner concept isn't really super useful. We barely use it anymore, but we do have it as a concept in DevTools in a couple of cases so this adds it for parity. However, this is mainly interesting because it could be used to wire up future owner-based stacks. I do this by outlining the DebugInfo for a Server Component (ReactComponentInfo). Then I just rely on Flight deduping to refer to that. I refer to the same thing by referential equality so that we can associate a Server Component parent in DebugInfo with an owner. If you suspend and replay a Server Component, we have to restore the same owner. To do that, I did a little ugly hack and stashed it on the thenable state object. Felt unnecessarily complicated to add a stateful wrapper for this one dev-only case. The owner could really be anything since it could be coming from a different implementation. Because this is the first time we have an owner other than Fiber, I have to fix up a bunch of places that assumes Fiber. I mainly did the `typeof owner.tag === 'number'` to assume it's a Fiber for now. This also doesn't actually add it to DevTools / RN Inspector yet. I just ignore them there for now. Because Server Components can be async the owner isn't tracked after an await. We need per-component AsyncLocalStorage for that. This can be done in a follow up.
This commit is contained in:
committed by
GitHub
parent
e3ebcd54b9
commit
f33a6b69c6
@@ -26,10 +26,7 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
|
||||
const {ReactCurrentDispatcher} = ReactSharedInternals;
|
||||
|
||||
let prefix;
|
||||
export function describeBuiltInComponentFrame(
|
||||
name: string,
|
||||
ownerFn: void | null | Function,
|
||||
): string {
|
||||
export function describeBuiltInComponentFrame(name: string): string {
|
||||
if (enableComponentStackLocations) {
|
||||
if (prefix === undefined) {
|
||||
// Extract the VM specific prefix used by each line.
|
||||
@@ -43,19 +40,12 @@ export function describeBuiltInComponentFrame(
|
||||
// We use the prefix to ensure our stacks line up with native stack frames.
|
||||
return '\n' + prefix + name;
|
||||
} else {
|
||||
let ownerName = null;
|
||||
if (__DEV__ && ownerFn) {
|
||||
ownerName = ownerFn.displayName || ownerFn.name || null;
|
||||
}
|
||||
return describeComponentFrame(name, ownerName);
|
||||
return describeComponentFrame(name);
|
||||
}
|
||||
}
|
||||
|
||||
export function describeDebugInfoFrame(name: string, env: ?string): string {
|
||||
return describeBuiltInComponentFrame(
|
||||
name + (env ? ' (' + env + ')' : ''),
|
||||
null,
|
||||
);
|
||||
return describeBuiltInComponentFrame(name + (env ? ' (' + env + ')' : ''));
|
||||
}
|
||||
|
||||
let reentry = false;
|
||||
@@ -298,29 +288,19 @@ export function describeNativeComponentFrame(
|
||||
return syntheticFrame;
|
||||
}
|
||||
|
||||
function describeComponentFrame(name: null | string, ownerName: null | string) {
|
||||
let sourceInfo = '';
|
||||
if (ownerName) {
|
||||
sourceInfo = ' (created by ' + ownerName + ')';
|
||||
}
|
||||
return '\n in ' + (name || 'Unknown') + sourceInfo;
|
||||
function describeComponentFrame(name: null | string) {
|
||||
return '\n in ' + (name || 'Unknown');
|
||||
}
|
||||
|
||||
export function describeClassComponentFrame(
|
||||
ctor: Function,
|
||||
ownerFn: void | null | Function,
|
||||
): string {
|
||||
export function describeClassComponentFrame(ctor: Function): string {
|
||||
if (enableComponentStackLocations) {
|
||||
return describeNativeComponentFrame(ctor, true);
|
||||
} else {
|
||||
return describeFunctionComponentFrame(ctor, ownerFn);
|
||||
return describeFunctionComponentFrame(ctor);
|
||||
}
|
||||
}
|
||||
|
||||
export function describeFunctionComponentFrame(
|
||||
fn: Function,
|
||||
ownerFn: void | null | Function,
|
||||
): string {
|
||||
export function describeFunctionComponentFrame(fn: Function): string {
|
||||
if (enableComponentStackLocations) {
|
||||
return describeNativeComponentFrame(fn, false);
|
||||
} else {
|
||||
@@ -328,11 +308,7 @@ export function describeFunctionComponentFrame(
|
||||
return '';
|
||||
}
|
||||
const name = fn.displayName || fn.name || null;
|
||||
let ownerName = null;
|
||||
if (__DEV__ && ownerFn) {
|
||||
ownerName = ownerFn.displayName || ownerFn.name || null;
|
||||
}
|
||||
return describeComponentFrame(name, ownerName);
|
||||
return describeComponentFrame(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,10 +317,7 @@ function shouldConstruct(Component: Function) {
|
||||
return !!(prototype && prototype.isReactComponent);
|
||||
}
|
||||
|
||||
export function describeUnknownElementTypeFrameInDEV(
|
||||
type: any,
|
||||
ownerFn: void | null | Function,
|
||||
): string {
|
||||
export function describeUnknownElementTypeFrameInDEV(type: any): string {
|
||||
if (!__DEV__) {
|
||||
return '';
|
||||
}
|
||||
@@ -355,32 +328,32 @@ export function describeUnknownElementTypeFrameInDEV(
|
||||
if (enableComponentStackLocations) {
|
||||
return describeNativeComponentFrame(type, shouldConstruct(type));
|
||||
} else {
|
||||
return describeFunctionComponentFrame(type, ownerFn);
|
||||
return describeFunctionComponentFrame(type);
|
||||
}
|
||||
}
|
||||
if (typeof type === 'string') {
|
||||
return describeBuiltInComponentFrame(type, ownerFn);
|
||||
return describeBuiltInComponentFrame(type);
|
||||
}
|
||||
switch (type) {
|
||||
case REACT_SUSPENSE_TYPE:
|
||||
return describeBuiltInComponentFrame('Suspense', ownerFn);
|
||||
return describeBuiltInComponentFrame('Suspense');
|
||||
case REACT_SUSPENSE_LIST_TYPE:
|
||||
return describeBuiltInComponentFrame('SuspenseList', ownerFn);
|
||||
return describeBuiltInComponentFrame('SuspenseList');
|
||||
}
|
||||
if (typeof type === 'object') {
|
||||
switch (type.$$typeof) {
|
||||
case REACT_FORWARD_REF_TYPE:
|
||||
return describeFunctionComponentFrame(type.render, ownerFn);
|
||||
return describeFunctionComponentFrame(type.render);
|
||||
case REACT_MEMO_TYPE:
|
||||
// Memo may contain any component type so we recursively resolve it.
|
||||
return describeUnknownElementTypeFrameInDEV(type.type, ownerFn);
|
||||
return describeUnknownElementTypeFrameInDEV(type.type);
|
||||
case REACT_LAZY_TYPE: {
|
||||
const lazyComponent: LazyComponent<any, any> = (type: any);
|
||||
const payload = lazyComponent._payload;
|
||||
const init = lazyComponent._init;
|
||||
try {
|
||||
// Lazy may contain any component type so we recursively resolve it.
|
||||
return describeUnknownElementTypeFrameInDEV(init(payload), ownerFn);
|
||||
return describeUnknownElementTypeFrameInDEV(init(payload));
|
||||
} catch (x) {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user