From d40ea875a42d5726e8a7e5a6f47db2dbe314957d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 1 Jul 2024 09:26:29 -0400 Subject: [PATCH] [Flight Server] Run Server Components in console.createTask when available (#30140) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Screenshot 2024-06-29 at 1 08 47 PM --- fixtures/flight/package.json | 2 +- .../react-server/src/ReactFlightServer.js | 42 +++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/fixtures/flight/package.json b/fixtures/flight/package.json index c0d8b4fea25db..659bd4894f6d9 100644 --- a/fixtures/flight/package.json +++ b/fixtures/flight/package.json @@ -71,7 +71,7 @@ "prebuild": "cp -r ../../build/oss-experimental/* ./node_modules/", "dev": "concurrently \"npm run dev:region\" \"npm run dev:global\"", "dev:global": "NODE_ENV=development BUILD_PATH=dist node --experimental-loader ./loader/global.js server/global", - "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", + "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", "start": "node scripts/build.js && concurrently \"npm run start:region\" \"npm run start:global\"", "start:global": "NODE_ENV=production node --experimental-loader ./loader/global.js server/global", "start:region": "NODE_ENV=production node --experimental-loader ./loader/region.js --conditions=react-server server/region", diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 7ff1e47897299..cb0d5ee395232 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -168,7 +168,7 @@ function getStack(error: Error): string { function initCallComponentFrame(): string { // Extract the stack frame of the callComponentInDEV function. - const error = callComponentInDEV(Error, 'react-stack-top-frame', {}); + const error = callComponentInDEV(Error, 'react-stack-top-frame', {}, null); const stack = getStack(error); const startIdx = stack.startsWith('Error: react-stack-top-frame\n') ? 29 : 0; const endIdx = stack.indexOf('\n', startIdx); @@ -991,6 +991,7 @@ function callComponentInDEV( Component: (p: Props, arg: void) => R, props: Props, componentDebugInfo: ReactComponentInfo, + debugTask: null | ConsoleTask, ): R { // The secondArg is always undefined in Server Components since refs error early. const secondArg = undefined; @@ -998,6 +999,18 @@ function callComponentInDEV( try { if (supportsComponentStorage) { // Run the component in an Async Context that tracks the current owner. + if (enableOwnerStacks && debugTask) { + return debugTask.run( + // $FlowFixMe[method-unbinding] + componentStorage.run.bind( + componentStorage, + componentDebugInfo, + Component, + props, + secondArg, + ), + ); + } return componentStorage.run( componentDebugInfo, Component, @@ -1005,6 +1018,9 @@ function callComponentInDEV( secondArg, ); } else { + if (enableOwnerStacks && debugTask) { + return debugTask.run(Component.bind(null, props, secondArg)); + } return Component(props, secondArg); } } finally { @@ -1028,6 +1044,7 @@ function renderFunctionComponent( props: Props, owner: null | ReactComponentInfo, // DEV-only stack: null | string, // DEV-only + debugTask: null | ConsoleTask, // DEV-only validated: number, // DEV-only ): ReactJSONValue { // Reset the task's thenable state before continuing, so that if a later @@ -1075,11 +1092,22 @@ function renderFunctionComponent( task.environmentName = componentEnv; if (enableOwnerStacks) { - warnForMissingKey(request, key, validated, componentDebugInfo); + warnForMissingKey( + request, + key, + validated, + componentDebugInfo, + debugTask, + ); } } prepareToUseHooksForComponent(prevThenableState, componentDebugInfo); - result = callComponentInDEV(Component, props, componentDebugInfo); + result = callComponentInDEV( + Component, + props, + componentDebugInfo, + debugTask, + ); } else { prepareToUseHooksForComponent(prevThenableState, null); // The secondArg is always undefined in Server Components since refs error early. @@ -1235,6 +1263,7 @@ function warnForMissingKey( key: null | string, validated: number, componentDebugInfo: ReactComponentInfo, + debugTask: null | ConsoleTask, ): void { if (__DEV__) { if (validated !== 2) { @@ -1267,6 +1296,7 @@ function warnForMissingKey( }, null, componentDebugInfo, + debugTask, ); } } @@ -1482,6 +1512,7 @@ function renderElement( props: any, owner: null | ReactComponentInfo, // DEV only stack: null | string, // DEV only + debugTask: null | ConsoleTask, // DEV only validated: number, // DEV only ): ReactJSONValue { if (ref !== null && ref !== undefined) { @@ -1514,6 +1545,7 @@ function renderElement( props, owner, stack, + debugTask, validated, ); } else if (type === REACT_FRAGMENT_TYPE && key === null) { @@ -1562,6 +1594,7 @@ function renderElement( props, owner, stack, + debugTask, validated, ); } @@ -1574,6 +1607,7 @@ function renderElement( props, owner, stack, + debugTask, validated, ); } @@ -1587,6 +1621,7 @@ function renderElement( props, owner, stack, + debugTask, validated, ); } @@ -2190,6 +2225,7 @@ function renderModelDestructive( ? element._debugStack : filterDebugStack(element._debugStack) : null, + __DEV__ && enableOwnerStacks ? element._debugTask : null, __DEV__ && enableOwnerStacks ? element._store.validated : 0, ); if (