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:
Sebastian Markbåge authored and GitHub committed 2024-04-05 12:48:52 -04:00
1 parent e3ebcd54b9
commit f33a6b69c6
20 files changed
+291 -158

No files matched your search

@@ -39,38 +39,30 @@ export function describeFiber(
ClassComponent,
} = workTagMap;
const owner: null | Function = __DEV__
? workInProgress._debugOwner
? workInProgress._debugOwner.type
: null
: null;
switch (workInProgress.tag) {
case HostComponent:
return describeBuiltInComponentFrame(workInProgress.type, owner);
return describeBuiltInComponentFrame(workInProgress.type);
case LazyComponent:
return describeBuiltInComponentFrame('Lazy', owner);
return describeBuiltInComponentFrame('Lazy');
case SuspenseComponent:
return describeBuiltInComponentFrame('Suspense', owner);
return describeBuiltInComponentFrame('Suspense');
case SuspenseListComponent:
return describeBuiltInComponentFrame('SuspenseList', owner);
return describeBuiltInComponentFrame('SuspenseList');
case FunctionComponent:
case IndeterminateComponent:
case SimpleMemoComponent:
return describeFunctionComponentFrame(
workInProgress.type,
owner,
currentDispatcherRef,
);
case ForwardRef:
return describeFunctionComponentFrame(
workInProgress.type.render,
owner,
currentDispatcherRef,
);
case ClassComponent:
return describeClassComponentFrame(
workInProgress.type,
owner,
currentDispatcherRef,
);
default: