Skip to content

Commit

Permalink
Track Owner for Server Components in DEV (#28753)
Browse files Browse the repository at this point in the history
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.

DiffTrain build for [f33a6b6](f33a6b6)
  • Loading branch information
sebmarkbage committed Apr 5, 2024
1 parent e6ea24b commit 75004cd
Show file tree
Hide file tree
Showing 30 changed files with 640 additions and 480 deletions.
36 changes: 16 additions & 20 deletions compiled/facebook-www/JSXDEVRuntime-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ if (__DEV__) {

var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
var prefix;
function describeBuiltInComponentFrame(name, ownerFn) {
function describeBuiltInComponentFrame(name) {
{
if (prefix === undefined) {
// Extract the VM specific prefix used by each line.
Expand Down Expand Up @@ -757,7 +757,7 @@ if (__DEV__) {

return syntheticFrame;
}
function describeFunctionComponentFrame(fn, ownerFn) {
function describeFunctionComponentFrame(fn) {
{
return describeNativeComponentFrame(fn, false);
}
Expand All @@ -768,7 +768,7 @@ if (__DEV__) {
return !!(prototype && prototype.isReactComponent);
}

function describeUnknownElementTypeFrameInDEV(type, ownerFn) {
function describeUnknownElementTypeFrameInDEV(type) {
if (type == null) {
return "";
}
Expand Down Expand Up @@ -798,7 +798,7 @@ if (__DEV__) {

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: {
var lazyComponent = type;
Expand All @@ -807,10 +807,7 @@ if (__DEV__) {

try {
// Lazy may contain any component type so we recursively resolve it.
return describeUnknownElementTypeFrameInDEV(
init(payload),
ownerFn
);
return describeUnknownElementTypeFrameInDEV(init(payload));
} catch (x) {}
}
}
Expand Down Expand Up @@ -862,7 +859,6 @@ if (__DEV__) {
function getContextName(type) {
return type.displayName || "Context";
}

function getComponentNameFromFiber(fiber) {
var tag = fiber.tag,
type = fiber.type;
Expand Down Expand Up @@ -1578,14 +1574,18 @@ if (__DEV__) {

if (
element &&
element._owner &&
element._owner != null &&
element._owner !== ReactCurrentOwner.current
) {
// Give the component that originally created this child.
childOwner =
" It was passed a child from " +
getComponentNameFromType(element._owner.type) +
".";
var ownerName = null;

if (typeof element._owner.tag === "number") {
ownerName = getComponentNameFromType(element._owner.type);
} else if (typeof element._owner.name === "string") {
ownerName = element._owner.name;
} // Give the component that originally created this child.

childOwner = " It was passed a child from " + ownerName + ".";
}

setCurrentlyValidatingElement(element);
Expand All @@ -1604,11 +1604,7 @@ if (__DEV__) {
function setCurrentlyValidatingElement(element) {
{
if (element) {
var owner = element._owner;
var stack = describeUnknownElementTypeFrameInDEV(
element.type,
owner ? owner.type : null
);
var stack = describeUnknownElementTypeFrameInDEV(element.type);
ReactDebugCurrentFrame.setExtraStackFrame(stack);
} else {
ReactDebugCurrentFrame.setExtraStackFrame(null);
Expand Down
36 changes: 16 additions & 20 deletions compiled/facebook-www/JSXDEVRuntime-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ if (__DEV__) {

var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
var prefix;
function describeBuiltInComponentFrame(name, ownerFn) {
function describeBuiltInComponentFrame(name) {
{
if (prefix === undefined) {
// Extract the VM specific prefix used by each line.
Expand Down Expand Up @@ -757,7 +757,7 @@ if (__DEV__) {

return syntheticFrame;
}
function describeFunctionComponentFrame(fn, ownerFn) {
function describeFunctionComponentFrame(fn) {
{
return describeNativeComponentFrame(fn, false);
}
Expand All @@ -768,7 +768,7 @@ if (__DEV__) {
return !!(prototype && prototype.isReactComponent);
}

function describeUnknownElementTypeFrameInDEV(type, ownerFn) {
function describeUnknownElementTypeFrameInDEV(type) {
if (type == null) {
return "";
}
Expand Down Expand Up @@ -798,7 +798,7 @@ if (__DEV__) {

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: {
var lazyComponent = type;
Expand All @@ -807,10 +807,7 @@ if (__DEV__) {

try {
// Lazy may contain any component type so we recursively resolve it.
return describeUnknownElementTypeFrameInDEV(
init(payload),
ownerFn
);
return describeUnknownElementTypeFrameInDEV(init(payload));
} catch (x) {}
}
}
Expand Down Expand Up @@ -862,7 +859,6 @@ if (__DEV__) {
function getContextName(type) {
return type.displayName || "Context";
}

function getComponentNameFromFiber(fiber) {
var tag = fiber.tag,
type = fiber.type;
Expand Down Expand Up @@ -1580,14 +1576,18 @@ if (__DEV__) {

if (
element &&
element._owner &&
element._owner != null &&
element._owner !== ReactCurrentOwner.current
) {
// Give the component that originally created this child.
childOwner =
" It was passed a child from " +
getComponentNameFromType(element._owner.type) +
".";
var ownerName = null;

if (typeof element._owner.tag === "number") {
ownerName = getComponentNameFromType(element._owner.type);
} else if (typeof element._owner.name === "string") {
ownerName = element._owner.name;
} // Give the component that originally created this child.

childOwner = " It was passed a child from " + ownerName + ".";
}

setCurrentlyValidatingElement(element);
Expand All @@ -1606,11 +1606,7 @@ if (__DEV__) {
function setCurrentlyValidatingElement(element) {
{
if (element) {
var owner = element._owner;
var stack = describeUnknownElementTypeFrameInDEV(
element.type,
owner ? owner.type : null
);
var stack = describeUnknownElementTypeFrameInDEV(element.type);
ReactDebugCurrentFrame.setExtraStackFrame(stack);
} else {
ReactDebugCurrentFrame.setExtraStackFrame(null);
Expand Down
2 changes: 1 addition & 1 deletion compiled/facebook-www/REVISION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e3ebcd54b98a4f8f5a9f7e63982fa75578b648ed
f33a6b69c6cb406ea0cc51d07bc4d3fd2d8d8744
38 changes: 17 additions & 21 deletions compiled/facebook-www/React-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ if (__DEV__) {
) {
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
}
var ReactVersion = "19.0.0-www-classic-943a0b57";
var ReactVersion = "19.0.0-www-classic-ff21e352";

// ATTENTION
// When adding new symbols to this file,
Expand Down Expand Up @@ -860,7 +860,7 @@ if (__DEV__) {

var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
var prefix;
function describeBuiltInComponentFrame(name, ownerFn) {
function describeBuiltInComponentFrame(name) {
{
if (prefix === undefined) {
// Extract the VM specific prefix used by each line.
Expand Down Expand Up @@ -1129,7 +1129,7 @@ if (__DEV__) {

return syntheticFrame;
}
function describeFunctionComponentFrame(fn, ownerFn) {
function describeFunctionComponentFrame(fn) {
{
return describeNativeComponentFrame(fn, false);
}
Expand All @@ -1140,7 +1140,7 @@ if (__DEV__) {
return !!(prototype && prototype.isReactComponent);
}

function describeUnknownElementTypeFrameInDEV(type, ownerFn) {
function describeUnknownElementTypeFrameInDEV(type) {
if (type == null) {
return "";
}
Expand Down Expand Up @@ -1170,7 +1170,7 @@ if (__DEV__) {

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: {
var lazyComponent = type;
Expand All @@ -1179,10 +1179,7 @@ if (__DEV__) {

try {
// Lazy may contain any component type so we recursively resolve it.
return describeUnknownElementTypeFrameInDEV(
init(payload),
ownerFn
);
return describeUnknownElementTypeFrameInDEV(init(payload));
} catch (x) {}
}
}
Expand Down Expand Up @@ -1234,7 +1231,6 @@ if (__DEV__) {
function getContextName(type) {
return type.displayName || "Context";
}

function getComponentNameFromFiber(fiber) {
var tag = fiber.tag,
type = fiber.type;
Expand Down Expand Up @@ -2302,14 +2298,18 @@ if (__DEV__) {

if (
element &&
element._owner &&
element._owner != null &&
element._owner !== ReactCurrentOwner.current
) {
// Give the component that originally created this child.
childOwner =
" It was passed a child from " +
getComponentNameFromType(element._owner.type) +
".";
var ownerName = null;

if (typeof element._owner.tag === "number") {
ownerName = getComponentNameFromType(element._owner.type);
} else if (typeof element._owner.name === "string") {
ownerName = element._owner.name;
} // Give the component that originally created this child.

childOwner = " It was passed a child from " + ownerName + ".";
}

setCurrentlyValidatingElement(element);
Expand All @@ -2328,11 +2328,7 @@ if (__DEV__) {
function setCurrentlyValidatingElement(element) {
{
if (element) {
var owner = element._owner;
var stack = describeUnknownElementTypeFrameInDEV(
element.type,
owner ? owner.type : null
);
var stack = describeUnknownElementTypeFrameInDEV(element.type);
ReactDebugCurrentFrame.setExtraStackFrame(stack);
} else {
ReactDebugCurrentFrame.setExtraStackFrame(null);
Expand Down
38 changes: 17 additions & 21 deletions compiled/facebook-www/React-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ if (__DEV__) {
) {
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
}
var ReactVersion = "19.0.0-www-modern-77bd3ad6";
var ReactVersion = "19.0.0-www-modern-99738e97";

// ATTENTION
// When adding new symbols to this file,
Expand Down Expand Up @@ -860,7 +860,7 @@ if (__DEV__) {

var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
var prefix;
function describeBuiltInComponentFrame(name, ownerFn) {
function describeBuiltInComponentFrame(name) {
{
if (prefix === undefined) {
// Extract the VM specific prefix used by each line.
Expand Down Expand Up @@ -1129,7 +1129,7 @@ if (__DEV__) {

return syntheticFrame;
}
function describeFunctionComponentFrame(fn, ownerFn) {
function describeFunctionComponentFrame(fn) {
{
return describeNativeComponentFrame(fn, false);
}
Expand All @@ -1140,7 +1140,7 @@ if (__DEV__) {
return !!(prototype && prototype.isReactComponent);
}

function describeUnknownElementTypeFrameInDEV(type, ownerFn) {
function describeUnknownElementTypeFrameInDEV(type) {
if (type == null) {
return "";
}
Expand Down Expand Up @@ -1170,7 +1170,7 @@ if (__DEV__) {

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: {
var lazyComponent = type;
Expand All @@ -1179,10 +1179,7 @@ if (__DEV__) {

try {
// Lazy may contain any component type so we recursively resolve it.
return describeUnknownElementTypeFrameInDEV(
init(payload),
ownerFn
);
return describeUnknownElementTypeFrameInDEV(init(payload));
} catch (x) {}
}
}
Expand Down Expand Up @@ -1234,7 +1231,6 @@ if (__DEV__) {
function getContextName(type) {
return type.displayName || "Context";
}

function getComponentNameFromFiber(fiber) {
var tag = fiber.tag,
type = fiber.type;
Expand Down Expand Up @@ -2304,14 +2300,18 @@ if (__DEV__) {

if (
element &&
element._owner &&
element._owner != null &&
element._owner !== ReactCurrentOwner.current
) {
// Give the component that originally created this child.
childOwner =
" It was passed a child from " +
getComponentNameFromType(element._owner.type) +
".";
var ownerName = null;

if (typeof element._owner.tag === "number") {
ownerName = getComponentNameFromType(element._owner.type);
} else if (typeof element._owner.name === "string") {
ownerName = element._owner.name;
} // Give the component that originally created this child.

childOwner = " It was passed a child from " + ownerName + ".";
}

setCurrentlyValidatingElement(element);
Expand All @@ -2330,11 +2330,7 @@ if (__DEV__) {
function setCurrentlyValidatingElement(element) {
{
if (element) {
var owner = element._owner;
var stack = describeUnknownElementTypeFrameInDEV(
element.type,
owner ? owner.type : null
);
var stack = describeUnknownElementTypeFrameInDEV(element.type);
ReactDebugCurrentFrame.setExtraStackFrame(stack);
} else {
ReactDebugCurrentFrame.setExtraStackFrame(null);
Expand Down
Loading

0 comments on commit 75004cd

Please sign in to comment.