@samitouri / QOS-React-1 / commits / d40ea875a4

[Flight Server] Run Server Components in console.createTask when available (#30140)

Same as #30142 but for Flight Server. This is rarely used but it does allow seeing component stacks when inspecting the Node.js server running Flight using `--inspect` and the Chrome DevTools. <img width="595" alt="Screenshot 2024-06-29 at 1 08 47 PM" src="https://github.com/facebook/react/assets/63648/7f643e1e-a251-4e4d-b015-22a22a47031d">

Sebastian Markbåge committed Jul 1, 2024 at 09:26 UTC d40ea875a42d5726e8a7e5a6f47db2dbe314957d
2 files changed +40 -4
fixtures/flight/package.json
+1 -1
@@ -71,7 +71,7 @@
71 "prebuild": "cp -r ../../build/oss-experimental/* ./node_modules/",
72 "dev": "concurrently \"npm run dev:region\" \"npm run dev:global\"",
73 "dev:global": "NODE_ENV=development BUILD_PATH=dist node --experimental-loader ./loader/global.js server/global",
74 - "dev:region": "NODE_ENV=development BUILD_PATH=dist nodemon --watch src --watch dist -- --enable-source-maps --experimental-loader ./loader/region.js --conditions=react-server server/region",
74 + "dev:region": "NODE_ENV=development BUILD_PATH=dist nodemon --watch src --watch dist -- --enable-source-maps --experimental-loader ./loader/region.js --conditions=react-server --inspect server/region",
75 "start": "node scripts/build.js && concurrently \"npm run start:region\" \"npm run start:global\"",
76 "start:global": "NODE_ENV=production node --experimental-loader ./loader/global.js server/global",
77 "start:region": "NODE_ENV=production node --experimental-loader ./loader/region.js --conditions=react-server server/region",
packages/react-server/src/ReactFlightServer.js
+39 -3
@@ -168,7 +168,7 @@ function getStack(error: Error): string {
168
169 function initCallComponentFrame(): string {
170 // Extract the stack frame of the callComponentInDEV function.
171 - const error = callComponentInDEV(Error, 'react-stack-top-frame', {});
171 + const error = callComponentInDEV(Error, 'react-stack-top-frame', {}, null);
172 const stack = getStack(error);
173 const startIdx = stack.startsWith('Error: react-stack-top-frame\n') ? 29 : 0;
174 const endIdx = stack.indexOf('\n', startIdx);
@@ -991,6 +991,7 @@ function callComponentInDEV<Props, R>(
991 Component: (p: Props, arg: void) => R,
992 props: Props,
993 componentDebugInfo: ReactComponentInfo,
994 + debugTask: null | ConsoleTask,
995 ): R {
996 // The secondArg is always undefined in Server Components since refs error early.
997 const secondArg = undefined;
@@ -998,6 +999,18 @@ function callComponentInDEV<Props, R>(
999 try {
1000 if (supportsComponentStorage) {
1001 // Run the component in an Async Context that tracks the current owner.
1002 + if (enableOwnerStacks && debugTask) {
1003 + return debugTask.run(
1004 + // $FlowFixMe[method-unbinding]
1005 + componentStorage.run.bind(
1006 + componentStorage,
1007 + componentDebugInfo,
1008 + Component,
1009 + props,
1010 + secondArg,
1011 + ),
1012 + );
1013 + }
1014 return componentStorage.run(
1015 componentDebugInfo,
1016 Component,
@@ -1005,6 +1018,9 @@ function callComponentInDEV<Props, R>(
1018 secondArg,
1019 );
1020 } else {
1021 + if (enableOwnerStacks && debugTask) {
1022 + return debugTask.run(Component.bind(null, props, secondArg));
1023 + }
1024 return Component(props, secondArg);
1025 }
1026 } finally {
@@ -1028,6 +1044,7 @@ function renderFunctionComponent<Props>(
1044 props: Props,
1045 owner: null | ReactComponentInfo, // DEV-only
1046 stack: null | string, // DEV-only
1047 + debugTask: null | ConsoleTask, // DEV-only
1048 validated: number, // DEV-only
1049 ): ReactJSONValue {
1050 // Reset the task's thenable state before continuing, so that if a later
@@ -1075,11 +1092,22 @@ function renderFunctionComponent<Props>(
1092 task.environmentName = componentEnv;
1093
1094 if (enableOwnerStacks) {
1078 - warnForMissingKey(request, key, validated, componentDebugInfo);
1095 + warnForMissingKey(
1096 + request,
1097 + key,
1098 + validated,
1099 + componentDebugInfo,
1100 + debugTask,
1101 + );
1102 }
1103 }
1104 prepareToUseHooksForComponent(prevThenableState, componentDebugInfo);
1082 - result = callComponentInDEV(Component, props, componentDebugInfo);
1105 + result = callComponentInDEV(
1106 + Component,
1107 + props,
1108 + componentDebugInfo,
1109 + debugTask,
1110 + );
1111 } else {
1112 prepareToUseHooksForComponent(prevThenableState, null);
1113 // The secondArg is always undefined in Server Components since refs error early.
@@ -1235,6 +1263,7 @@ function warnForMissingKey(
1263 key: null | string,
1264 validated: number,
1265 componentDebugInfo: ReactComponentInfo,
1266 + debugTask: null | ConsoleTask,
1267 ): void {
1268 if (__DEV__) {
1269 if (validated !== 2) {
@@ -1267,6 +1296,7 @@ function warnForMissingKey(
1296 },
1297 null,
1298 componentDebugInfo,
1299 + debugTask,
1300 );
1301 }
1302 }
@@ -1482,6 +1512,7 @@ function renderElement(
1512 props: any,
1513 owner: null | ReactComponentInfo, // DEV only
1514 stack: null | string, // DEV only
1515 + debugTask: null | ConsoleTask, // DEV only
1516 validated: number, // DEV only
1517 ): ReactJSONValue {
1518 if (ref !== null && ref !== undefined) {
@@ -1514,6 +1545,7 @@ function renderElement(
1545 props,
1546 owner,
1547 stack,
1548 + debugTask,
1549 validated,
1550 );
1551 } else if (type === REACT_FRAGMENT_TYPE && key === null) {
@@ -1562,6 +1594,7 @@ function renderElement(
1594 props,
1595 owner,
1596 stack,
1597 + debugTask,
1598 validated,
1599 );
1600 }
@@ -1574,6 +1607,7 @@ function renderElement(
1607 props,
1608 owner,
1609 stack,
1610 + debugTask,
1611 validated,
1612 );
1613 }
@@ -1587,6 +1621,7 @@ function renderElement(
1621 props,
1622 owner,
1623 stack,
1624 + debugTask,
1625 validated,
1626 );
1627 }
@@ -2190,6 +2225,7 @@ function renderModelDestructive(
2225 ? element._debugStack
2226 : filterDebugStack(element._debugStack)
2227 : null,
2228 + __DEV__ && enableOwnerStacks ? element._debugTask : null,
2229 __DEV__ && enableOwnerStacks ? element._store.validated : 0,
2230 );
2231 if (