@samitouri / QOS-React / commits / 3f93ca1c8d

[Fiber] Transfer `_debugInfo` from Arrays, Lazy, Thenables and Elements to the inner Fibers. (#28286)

That way we can use it for debug information like component stacks and DevTools. I used an extra stack argument in Child Fiber to track this as it's flowing down since it's not just elements where we have this info readily available but parent arrays and lazy can merge this into the Fiber too. It's not great that this is a dev-only argument and I could track it globally but seems more likely to make mistakes. It is possible for the same debug info to appear for multiple child fibers like when it's attached to a fragment or a lazy that resolves to a fragment at the root. The object identity could be used in these scenarios to infer if that's really one server component that's a parent of all children or if each child has a server component with the same name. This is effectively a public API because you can use it to stash information on Promises from a third-party service - not just Server Components. I started outline the types for this for some things I was planning to add but it's not final. I was also planning on storing it from `use(thenable)` for when you suspend on a Promise. However, I realized that there's no Hook instance for those to stash it on. So it might need a separate data structure to stash the previous pass over of `use()` that resets each render. No tests yet since I didn't want to test internals but it'll be covered once we have debugging features like component stacks.

Sebastian Markbåge committed Feb 12, 2024 at 14:56 UTC 3f93ca1c8dec1fd85df4dbb748a2df9438fc699f
8 files changed +228 -29
packages/react-client/src/ReactFlightClient.js
+7 -5
@@ -7,7 +7,12 @@
7 * @flow
8 */
9
10 -import type {Thenable} from 'shared/ReactTypes';
10 +import type {
11 + Thenable,
12 + ReactDebugInfo,
13 + ReactComponentInfo,
14 + ReactAsyncInfo,
15 +} from 'shared/ReactTypes';
16 import type {LazyComponent} from 'react/src/ReactLazy';
17
18 import type {
@@ -76,9 +81,6 @@ const RESOLVED_MODULE = 'resolved_module';
81 const INITIALIZED = 'fulfilled';
82 const ERRORED = 'rejected';
83
79 -// Dev-only
80 -type ReactDebugInfo = Array<{+name?: string, +env?: string}>;
81 -
84 type PendingChunk<T> = {
85 status: 'pending',
86 value: null | Array<(T) => mixed>,
@@ -1014,7 +1016,7 @@ function resolveHint<Code: HintCode>(
1016 function resolveDebugInfo(
1017 response: Response,
1018 id: number,
1017 - debugInfo: {name: string},
1019 + debugInfo: ReactComponentInfo | ReactAsyncInfo,
1020 ): void {
1021 if (!__DEV__) {
1022 // These errors should never make it into a build so we don't need to encode them in codes.json
packages/react-reconciler/src/ReactChildFiber.js
+189 -17
@@ -8,7 +8,12 @@
8 */
9
10 import type {ReactElement} from 'shared/ReactElementType';
11 -import type {ReactPortal, Thenable, ReactContext} from 'shared/ReactTypes';
11 +import type {
12 + ReactPortal,
13 + Thenable,
14 + ReactContext,
15 + ReactDebugInfo,
16 +} from 'shared/ReactTypes';
17 import type {Fiber} from './ReactInternalTypes';
18 import type {Lanes} from './ReactFiberLane';
19 import type {ThenableState} from './ReactFiberThenable';
@@ -50,6 +55,25 @@ import {readContextDuringReconcilation} from './ReactFiberNewContext';
55 let thenableState: ThenableState | null = null;
56 let thenableIndexCounter: number = 0;
57
58 +function mergeDebugInfo(
59 + outer: ReactDebugInfo | null,
60 + inner: ReactDebugInfo | null | void,
61 +): ReactDebugInfo | null {
62 + if (!__DEV__) {
63 + return null;
64 + }
65 + if (inner == null) {
66 + return outer;
67 + } else if (outer === null) {
68 + return inner;
69 + } else {
70 + // If we have two debugInfo, we need to create a new one. This makes the array no longer
71 + // live so we'll miss any future updates if we received more so ideally we should always
72 + // do this after both have fully resolved/unsuspended.
73 + return outer.concat(inner);
74 + }
75 +}
76 +
77 let didWarnAboutMaps;
78 let didWarnAboutGenerators;
79 let didWarnAboutStringRefs;
@@ -387,16 +411,23 @@ function createChildReconciler(
411 current: Fiber | null,
412 textContent: string,
413 lanes: Lanes,
414 + debugInfo: ReactDebugInfo | null,
415 ) {
416 if (current === null || current.tag !== HostText) {
417 // Insert
418 const created = createFiberFromText(textContent, returnFiber.mode, lanes);
419 created.return = returnFiber;
420 + if (__DEV__) {
421 + created._debugInfo = debugInfo;
422 + }
423 return created;
424 } else {
425 // Update
426 const existing = useFiber(current, textContent);
427 existing.return = returnFiber;
428 + if (__DEV__) {
429 + existing._debugInfo = debugInfo;
430 + }
431 return existing;
432 }
433 }
@@ -406,6 +437,7 @@ function createChildReconciler(
437 current: Fiber | null,
438 element: ReactElement,
439 lanes: Lanes,
440 + debugInfo: ReactDebugInfo | null,
441 ): Fiber {
442 const elementType = element.type;
443 if (elementType === REACT_FRAGMENT_TYPE) {
@@ -415,6 +447,7 @@ function createChildReconciler(
447 element.props.children,
448 lanes,
449 element.key,
450 + debugInfo,
451 );
452 }
453 if (current !== null) {
@@ -439,6 +472,7 @@ function createChildReconciler(
472 existing.return = returnFiber;
473 if (__DEV__) {
474 existing._debugOwner = element._owner;
475 + existing._debugInfo = debugInfo;
476 }
477 return existing;
478 }
@@ -447,6 +481,9 @@ function createChildReconciler(
481 const created = createFiberFromElement(element, returnFiber.mode, lanes);
482 created.ref = coerceRef(returnFiber, current, element);
483 created.return = returnFiber;
484 + if (__DEV__) {
485 + created._debugInfo = debugInfo;
486 + }
487 return created;
488 }
489
@@ -455,6 +492,7 @@ function createChildReconciler(
492 current: Fiber | null,
493 portal: ReactPortal,
494 lanes: Lanes,
495 + debugInfo: ReactDebugInfo | null,
496 ): Fiber {
497 if (
498 current === null ||
@@ -465,11 +503,17 @@ function createChildReconciler(
503 // Insert
504 const created = createFiberFromPortal(portal, returnFiber.mode, lanes);
505 created.return = returnFiber;
506 + if (__DEV__) {
507 + created._debugInfo = debugInfo;
508 + }
509 return created;
510 } else {
511 // Update
512 const existing = useFiber(current, portal.children || []);
513 existing.return = returnFiber;
514 + if (__DEV__) {
515 + existing._debugInfo = debugInfo;
516 + }
517 return existing;
518 }
519 }
@@ -480,6 +524,7 @@ function createChildReconciler(
524 fragment: Iterable<React$Node>,
525 lanes: Lanes,
526 key: null | string,
527 + debugInfo: null | ReactDebugInfo,
528 ): Fiber {
529 if (current === null || current.tag !== Fragment) {
530 // Insert
@@ -490,11 +535,17 @@ function createChildReconciler(
535 key,
536 );
537 created.return = returnFiber;
538 + if (__DEV__) {
539 + created._debugInfo = debugInfo;
540 + }
541 return created;
542 } else {
543 // Update
544 const existing = useFiber(current, fragment);
545 existing.return = returnFiber;
546 + if (__DEV__) {
547 + existing._debugInfo = debugInfo;
548 + }
549 return existing;
550 }
551 }
@@ -503,6 +554,7 @@ function createChildReconciler(
554 returnFiber: Fiber,
555 newChild: any,
556 lanes: Lanes,
557 + debugInfo: ReactDebugInfo | null,
558 ): Fiber | null {
559 if (
560 (typeof newChild === 'string' && newChild !== '') ||
@@ -517,6 +569,9 @@ function createChildReconciler(
569 lanes,
570 );
571 created.return = returnFiber;
572 + if (__DEV__) {
573 + created._debugInfo = debugInfo;
574 + }
575 return created;
576 }
577
@@ -530,6 +585,9 @@ function createChildReconciler(
585 );
586 created.ref = coerceRef(returnFiber, null, newChild);
587 created.return = returnFiber;
588 + if (__DEV__) {
589 + created._debugInfo = mergeDebugInfo(debugInfo, newChild._debugInfo);
590 + }
591 return created;
592 }
593 case REACT_PORTAL_TYPE: {
@@ -539,12 +597,20 @@ function createChildReconciler(
597 lanes,
598 );
599 created.return = returnFiber;
600 + if (__DEV__) {
601 + created._debugInfo = debugInfo;
602 + }
603 return created;
604 }
605 case REACT_LAZY_TYPE: {
606 const payload = newChild._payload;
607 const init = newChild._init;
547 - return createChild(returnFiber, init(payload), lanes);
608 + return createChild(
609 + returnFiber,
610 + init(payload),
611 + lanes,
612 + mergeDebugInfo(debugInfo, newChild._debugInfo), // call merge after init
613 + );
614 }
615 }
616
@@ -556,6 +622,9 @@ function createChildReconciler(
622 null,
623 );
624 created.return = returnFiber;
625 + if (__DEV__) {
626 + created._debugInfo = mergeDebugInfo(debugInfo, newChild._debugInfo);
627 + }
628 return created;
629 }
630
@@ -564,7 +633,12 @@ function createChildReconciler(
633 // Unwrap the inner value and recursively call this function again.
634 if (typeof newChild.then === 'function') {
635 const thenable: Thenable<any> = (newChild: any);
567 - return createChild(returnFiber, unwrapThenable(thenable), lanes);
636 + return createChild(
637 + returnFiber,
638 + unwrapThenable(thenable),
639 + lanes,
640 + mergeDebugInfo(debugInfo, newChild._debugInfo),
641 + );
642 }
643
644 if (newChild.$$typeof === REACT_CONTEXT_TYPE) {
@@ -573,6 +647,7 @@ function createChildReconciler(
647 returnFiber,
648 readContextDuringReconcilation(returnFiber, context, lanes),
649 lanes,
650 + debugInfo,
651 );
652 }
653
@@ -593,6 +668,7 @@ function createChildReconciler(
668 oldFiber: Fiber | null,
669 newChild: any,
670 lanes: Lanes,
671 + debugInfo: null | ReactDebugInfo,
672 ): Fiber | null {
673 // Update the fiber if the keys match, otherwise return null.
674 const key = oldFiber !== null ? oldFiber.key : null;
@@ -607,21 +683,39 @@ function createChildReconciler(
683 if (key !== null) {
684 return null;
685 }
610 - return updateTextNode(returnFiber, oldFiber, '' + newChild, lanes);
686 + return updateTextNode(
687 + returnFiber,
688 + oldFiber,
689 + '' + newChild,
690 + lanes,
691 + debugInfo,
692 + );
693 }
694
695 if (typeof newChild === 'object' && newChild !== null) {
696 switch (newChild.$$typeof) {
697 case REACT_ELEMENT_TYPE: {
698 if (newChild.key === key) {
617 - return updateElement(returnFiber, oldFiber, newChild, lanes);
699 + return updateElement(
700 + returnFiber,
701 + oldFiber,
702 + newChild,
703 + lanes,
704 + mergeDebugInfo(debugInfo, newChild._debugInfo),
705 + );
706 } else {
707 return null;
708 }
709 }
710 case REACT_PORTAL_TYPE: {
711 if (newChild.key === key) {
624 - return updatePortal(returnFiber, oldFiber, newChild, lanes);
712 + return updatePortal(
713 + returnFiber,
714 + oldFiber,
715 + newChild,
716 + lanes,
717 + debugInfo,
718 + );
719 } else {
720 return null;
721 }
@@ -629,7 +723,13 @@ function createChildReconciler(
723 case REACT_LAZY_TYPE: {
724 const payload = newChild._payload;
725 const init = newChild._init;
632 - return updateSlot(returnFiber, oldFiber, init(payload), lanes);
726 + return updateSlot(
727 + returnFiber,
728 + oldFiber,
729 + init(payload),
730 + lanes,
731 + mergeDebugInfo(debugInfo, newChild._debugInfo),
732 + );
733 }
734 }
735
@@ -638,7 +738,14 @@ function createChildReconciler(
738 return null;
739 }
740
641 - return updateFragment(returnFiber, oldFiber, newChild, lanes, null);
741 + return updateFragment(
742 + returnFiber,
743 + oldFiber,
744 + newChild,
745 + lanes,
746 + null,
747 + mergeDebugInfo(debugInfo, newChild._debugInfo),
748 + );
749 }
750
751 // Usable node types
@@ -651,6 +758,7 @@ function createChildReconciler(
758 oldFiber,
759 unwrapThenable(thenable),
760 lanes,
761 + debugInfo,
762 );
763 }
764
@@ -661,6 +769,7 @@ function createChildReconciler(
769 oldFiber,
770 readContextDuringReconcilation(returnFiber, context, lanes),
771 lanes,
772 + debugInfo,
773 );
774 }
775
@@ -682,6 +791,7 @@ function createChildReconciler(
791 newIdx: number,
792 newChild: any,
793 lanes: Lanes,
794 + debugInfo: ReactDebugInfo | null,
795 ): Fiber | null {
796 if (
797 (typeof newChild === 'string' && newChild !== '') ||
@@ -690,7 +800,13 @@ function createChildReconciler(
800 // Text nodes don't have keys, so we neither have to check the old nor
801 // new node for the key. If both are text nodes, they match.
802 const matchedFiber = existingChildren.get(newIdx) || null;
693 - return updateTextNode(returnFiber, matchedFiber, '' + newChild, lanes);
803 + return updateTextNode(
804 + returnFiber,
805 + matchedFiber,
806 + '' + newChild,
807 + lanes,
808 + debugInfo,
809 + );
810 }
811
812 if (typeof newChild === 'object' && newChild !== null) {
@@ -700,14 +816,26 @@ function createChildReconciler(
816 existingChildren.get(
817 newChild.key === null ? newIdx : newChild.key,
818 ) || null;
703 - return updateElement(returnFiber, matchedFiber, newChild, lanes);
819 + return updateElement(
820 + returnFiber,
821 + matchedFiber,
822 + newChild,
823 + lanes,
824 + mergeDebugInfo(debugInfo, newChild._debugInfo),
825 + );
826 }
827 case REACT_PORTAL_TYPE: {
828 const matchedFiber =
829 existingChildren.get(
830 newChild.key === null ? newIdx : newChild.key,
831 ) || null;
710 - return updatePortal(returnFiber, matchedFiber, newChild, lanes);
832 + return updatePortal(
833 + returnFiber,
834 + matchedFiber,
835 + newChild,
836 + lanes,
837 + debugInfo,
838 + );
839 }
840 case REACT_LAZY_TYPE:
841 const payload = newChild._payload;
@@ -718,12 +846,20 @@ function createChildReconciler(
846 newIdx,
847 init(payload),
848 lanes,
849 + mergeDebugInfo(debugInfo, newChild._debugInfo),
850 );
851 }
852
853 if (isArray(newChild) || getIteratorFn(newChild)) {
854 const matchedFiber = existingChildren.get(newIdx) || null;
726 - return updateFragment(returnFiber, matchedFiber, newChild, lanes, null);
855 + return updateFragment(
856 + returnFiber,
857 + matchedFiber,
858 + newChild,
859 + lanes,
860 + null,
861 + mergeDebugInfo(debugInfo, newChild._debugInfo),
862 + );
863 }
864
865 // Usable node types
@@ -737,6 +873,7 @@ function createChildReconciler(
873 newIdx,
874 unwrapThenable(thenable),
875 lanes,
876 + debugInfo,
877 );
878 }
879
@@ -748,6 +885,7 @@ function createChildReconciler(
885 newIdx,
886 readContextDuringReconcilation(returnFiber, context, lanes),
887 lanes,
888 + debugInfo,
889 );
890 }
891
@@ -818,6 +956,7 @@ function createChildReconciler(
956 currentFirstChild: Fiber | null,
957 newChildren: Array<any>,
958 lanes: Lanes,
959 + debugInfo: ReactDebugInfo | null,
960 ): Fiber | null {
961 // This algorithm can't optimize by searching from both ends since we
962 // don't have backpointers on fibers. I'm trying to see how far we can get
@@ -866,6 +1005,7 @@ function createChildReconciler(
1005 oldFiber,
1006 newChildren[newIdx],
1007 lanes,
1008 + debugInfo,
1009 );
1010 if (newFiber === null) {
1011 // TODO: This breaks on empty slots like null children. That's
@@ -913,7 +1053,12 @@ function createChildReconciler(
1053 // If we don't have any more existing children we can choose a fast path
1054 // since the rest will all be insertions.
1055 for (; newIdx < newChildren.length; newIdx++) {
916 - const newFiber = createChild(returnFiber, newChildren[newIdx], lanes);
1056 + const newFiber = createChild(
1057 + returnFiber,
1058 + newChildren[newIdx],
1059 + lanes,
1060 + debugInfo,
1061 + );
1062 if (newFiber === null) {
1063 continue;
1064 }
@@ -944,6 +1089,7 @@ function createChildReconciler(
1089 newIdx,
1090 newChildren[newIdx],
1091 lanes,
1092 + debugInfo,
1093 );
1094 if (newFiber !== null) {
1095 if (shouldTrackSideEffects) {
@@ -985,6 +1131,7 @@ function createChildReconciler(
1131 currentFirstChild: Fiber | null,
1132 newChildrenIterable: Iterable<mixed>,
1133 lanes: Lanes,
1134 + debugInfo: ReactDebugInfo | null,
1135 ): Fiber | null {
1136 // This is the same implementation as reconcileChildrenArray(),
1137 // but using the iterator instead.
@@ -1068,7 +1215,13 @@ function createChildReconciler(
1215 } else {
1216 nextOldFiber = oldFiber.sibling;
1217 }
1071 - const newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes);
1218 + const newFiber = updateSlot(
1219 + returnFiber,
1220 + oldFiber,
1221 + step.value,
1222 + lanes,
1223 + debugInfo,
1224 + );
1225 if (newFiber === null) {
1226 // TODO: This breaks on empty slots like null children. That's
1227 // unfortunate because it triggers the slow path all the time. We need
@@ -1115,7 +1268,7 @@ function createChildReconciler(
1268 // If we don't have any more existing children we can choose a fast path
1269 // since the rest will all be insertions.
1270 for (; !step.done; newIdx++, step = newChildren.next()) {
1118 - const newFiber = createChild(returnFiber, step.value, lanes);
1271 + const newFiber = createChild(returnFiber, step.value, lanes, debugInfo);
1272 if (newFiber === null) {
1273 continue;
1274 }
@@ -1146,6 +1299,7 @@ function createChildReconciler(
1299 newIdx,
1300 step.value,
1301 lanes,
1302 + debugInfo,
1303 );
1304 if (newFiber !== null) {
1305 if (shouldTrackSideEffects) {
@@ -1211,6 +1365,7 @@ function createChildReconciler(
1365 currentFirstChild: Fiber | null,
1366 element: ReactElement,
1367 lanes: Lanes,
1368 + debugInfo: ReactDebugInfo | null,
1369 ): Fiber {
1370 const key = element.key;
1371 let child = currentFirstChild;
@@ -1226,6 +1381,7 @@ function createChildReconciler(
1381 existing.return = returnFiber;
1382 if (__DEV__) {
1383 existing._debugOwner = element._owner;
1384 + existing._debugInfo = debugInfo;
1385 }
1386 return existing;
1387 }
@@ -1251,6 +1407,7 @@ function createChildReconciler(
1407 existing.return = returnFiber;
1408 if (__DEV__) {
1409 existing._debugOwner = element._owner;
1410 + existing._debugInfo = debugInfo;
1411 }
1412 return existing;
1413 }
@@ -1272,11 +1429,17 @@ function createChildReconciler(
1429 element.key,
1430 );
1431 created.return = returnFiber;
1432 + if (__DEV__) {
1433 + created._debugInfo = debugInfo;
1434 + }
1435 return created;
1436 } else {
1437 const created = createFiberFromElement(element, returnFiber.mode, lanes);
1438 created.ref = coerceRef(returnFiber, currentFirstChild, element);
1439 created.return = returnFiber;
1440 + if (__DEV__) {
1441 + created._debugInfo = debugInfo;
1442 + }
1443 return created;
1444 }
1445 }
@@ -1286,6 +1449,7 @@ function createChildReconciler(
1449 currentFirstChild: Fiber | null,
1450 portal: ReactPortal,
1451 lanes: Lanes,
1452 + debugInfo: ReactDebugInfo | null,
1453 ): Fiber {
1454 const key = portal.key;
1455 let child = currentFirstChild;
@@ -1325,6 +1489,7 @@ function createChildReconciler(
1489 currentFirstChild: Fiber | null,
1490 newChild: any,
1491 lanes: Lanes,
1492 + debugInfo: ReactDebugInfo | null,
1493 ): Fiber | null {
1494 // This function is not recursive.
1495 // If the top level item is an array, we treat it as a set of children,
@@ -1354,6 +1519,7 @@ function createChildReconciler(
1519 currentFirstChild,
1520 newChild,
1521 lanes,
1522 + mergeDebugInfo(debugInfo, newChild._debugInfo),
1523 ),
1524 );
1525 case REACT_PORTAL_TYPE:
@@ -1363,17 +1529,18 @@ function createChildReconciler(
1529 currentFirstChild,
1530 newChild,
1531 lanes,
1532 + debugInfo,
1533 ),
1534 );
1535 case REACT_LAZY_TYPE:
1536 const payload = newChild._payload;
1537 const init = newChild._init;
1371 - // TODO: This function is supposed to be non-recursive.
1372 - return reconcileChildFibers(
1538 + return reconcileChildFibersImpl(
1539 returnFiber,
1540 currentFirstChild,
1541 init(payload),
1542 lanes,
1543 + mergeDebugInfo(debugInfo, newChild._debugInfo),
1544 );
1545 }
1546
@@ -1383,6 +1550,7 @@ function createChildReconciler(
1550 currentFirstChild,
1551 newChild,
1552 lanes,
1553 + mergeDebugInfo(debugInfo, newChild._debugInfo),
1554 );
1555 }
1556
@@ -1392,6 +1560,7 @@ function createChildReconciler(
1560 currentFirstChild,
1561 newChild,
1562 lanes,
1563 + mergeDebugInfo(debugInfo, newChild._debugInfo),
1564 );
1565 }
1566
@@ -1418,6 +1587,7 @@ function createChildReconciler(
1587 currentFirstChild,
1588 unwrapThenable(thenable),
1589 lanes,
1590 + mergeDebugInfo(debugInfo, thenable._debugInfo),
1591 );
1592 }
1593
@@ -1428,6 +1598,7 @@ function createChildReconciler(
1598 currentFirstChild,
1599 readContextDuringReconcilation(returnFiber, context, lanes),
1600 lanes,
1601 + debugInfo,
1602 );
1603 }
1604
@@ -1472,6 +1643,7 @@ function createChildReconciler(
1643 currentFirstChild,
1644 newChild,
1645 lanes,
1646 + null, // debugInfo
1647 );
1648 thenableState = null;
1649 // Don't bother to reset `thenableIndexCounter` to 0 because it always gets
packages/react-reconciler/src/ReactFiber.js
+3 -1
@@ -201,7 +201,7 @@ function FiberNode(
201
202 if (__DEV__) {
203 // This isn't directly used but is handy for debugging internals:
204 -
204 + this._debugInfo = null;
205 this._debugOwner = null;
206 this._debugNeedsRemount = false;
207 this._debugHookTypes = null;
@@ -347,6 +347,7 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
347 }
348
349 if (__DEV__) {
350 + workInProgress._debugInfo = current._debugInfo;
351 workInProgress._debugNeedsRemount = current._debugNeedsRemount;
352 switch (workInProgress.tag) {
353 case IndeterminateComponent:
@@ -911,6 +912,7 @@ export function assignFiberPropertiesInDEV(
912 target.treeBaseDuration = source.treeBaseDuration;
913 }
914
915 + target._debugInfo = source._debugInfo;
916 target._debugOwner = source._debugOwner;
917 target._debugNeedsRemount = source._debugNeedsRemount;
918 target._debugHookTypes = source._debugHookTypes;
packages/react-reconciler/src/ReactFiberBeginWork.js
+4
@@ -3760,6 +3760,10 @@ function remountFiber(
3760 newWorkInProgress.return = oldWorkInProgress.return;
3761 newWorkInProgress.ref = oldWorkInProgress.ref;
3762
3763 + if (__DEV__) {
3764 + newWorkInProgress._debugInfo = oldWorkInProgress._debugInfo;
3765 + }
3766 +
3767 // Replace the child/sibling pointers above it.
3768 if (oldWorkInProgress === returnFiber.child) {
3769 returnFiber.child = newWorkInProgress;
packages/react-reconciler/src/ReactInternalTypes.js
+2
@@ -15,6 +15,7 @@ import type {
15 Usable,
16 ReactFormState,
17 Awaited,
18 + ReactDebugInfo,
19 } from 'shared/ReactTypes';
20 import type {WorkTag} from './ReactWorkTags';
21 import type {TypeOfMode} from './ReactTypeOfMode';
@@ -199,6 +200,7 @@ export type Fiber = {
200 // to be the same as work in progress.
201 // __DEV__ only
202
203 + _debugInfo?: ReactDebugInfo | null,
204 _debugOwner?: Fiber | null,
205 _debugIsCurrentlyTiming?: boolean,
206 _debugNeedsRemount?: boolean,
packages/react-server/src/ReactFlightServer.js
+4 -4
@@ -52,6 +52,9 @@ import type {
52 PendingThenable,
53 FulfilledThenable,
54 RejectedThenable,
55 + ReactDebugInfo,
56 + ReactComponentInfo,
57 + ReactAsyncInfo,
58 } from 'shared/ReactTypes';
59 import type {LazyComponent} from 'react/src/ReactLazy';
60
@@ -107,9 +110,6 @@ import {SuspenseException, getSuspendedThenable} from './ReactFlightThenable';
110
111 initAsyncDebugInfo();
112
110 -// Dev-only
111 -type ReactDebugInfo = Array<{+name?: string, +env?: string}>;
112 -
113 const ObjectPrototype = Object.prototype;
114
115 type JSONValue =
@@ -1731,7 +1731,7 @@ function emitModelChunk(request: Request, id: number, json: string): void {
1731 function emitDebugChunk(
1732 request: Request,
1733 id: number,
1734 - debugInfo: {+name?: string, +env?: string},
1734 + debugInfo: ReactComponentInfo | ReactAsyncInfo,
1735 ): void {
1736 if (!__DEV__) {
1737 // These errors should never make it into a build so we don't need to encode them in codes.json
packages/react/src/ReactLazy.js
+2 -2
@@ -7,7 +7,7 @@
7 * @flow
8 */
9
10 -import type {Wakeable, Thenable} from 'shared/ReactTypes';
10 +import type {Wakeable, Thenable, ReactDebugInfo} from 'shared/ReactTypes';
11
12 import {REACT_LAZY_TYPE} from 'shared/ReactSymbols';
13
@@ -46,7 +46,7 @@ export type LazyComponent<T, P> = {
46 $$typeof: symbol | number,
47 _payload: P,
48 _init: (payload: P) => T,
49 - _debugInfo?: null | Array<{+name?: string, +env?: string}>,
49 + _debugInfo?: null | ReactDebugInfo,
50 };
51
52 function lazyInitializer<T>(payload: Payload<T>): T {
packages/shared/ReactTypes.js
+17
@@ -111,20 +111,24 @@ interface ThenableImpl<T> {
111 }
112 interface UntrackedThenable<T> extends ThenableImpl<T> {
113 status?: void;
114 + _debugInfo?: null | ReactDebugInfo;
115 }
116
117 export interface PendingThenable<T> extends ThenableImpl<T> {
118 status: 'pending';
119 + _debugInfo?: null | ReactDebugInfo;
120 }
121
122 export interface FulfilledThenable<T> extends ThenableImpl<T> {
123 status: 'fulfilled';
124 value: T;
125 + _debugInfo?: null | ReactDebugInfo;
126 }
127
128 export interface RejectedThenable<T> extends ThenableImpl<T> {
129 status: 'rejected';
130 reason: mixed;
131 + _debugInfo?: null | ReactDebugInfo;
132 }
133
134 export type Thenable<T> =
@@ -173,3 +177,16 @@ export type Awaited<T> = T extends null | void
177 : empty // the argument to `then` was not callable.
178 : T // argument was not an object
179 : T; // non-thenable
180 +
181 +export type ReactComponentInfo = {
182 + +name?: string,
183 + +env?: string,
184 +};
185 +
186 +export type ReactAsyncInfo = {
187 + +started?: number,
188 + +completed?: number,
189 + +stack?: string,
190 +};
191 +
192 +export type ReactDebugInfo = Array<ReactComponentInfo | ReactAsyncInfo>;