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 1/2] [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 ( From e6783e7cc94bceb5bba92b79ff71f44f630e1c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 1 Jul 2024 09:50:45 -0400 Subject: [PATCH 2/2] [Fizz] Run console.createTask during SSR when available (#30142) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same as #30140 but for Fizz. This is rarely used but it does allow seeing component stacks when inspecting the Node.js server running Fizz using `--inspect` and the Chrome DevTools. Screenshot 2024-06-29 at 4 08 22 PM --- fixtures/flight/package.json | 4 +- packages/react-server/src/ReactFizzServer.js | 39 ++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/fixtures/flight/package.json b/fixtures/flight/package.json index 659bd4894f6d9..f07b667dab910 100644 --- a/fixtures/flight/package.json +++ b/fixtures/flight/package.json @@ -70,8 +70,8 @@ "predev": "cp -r ../../build/oss-experimental/* ./node_modules/", "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 --inspect server/region", + "dev:global": "NODE_ENV=development BUILD_PATH=dist node --experimental-loader ./loader/global.js --inspect=127.0.0.1:9230 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 --inspect=127.0.0.1:9229 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/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index 75b195e1e25fb..b5e9ed28fde52 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -150,6 +150,7 @@ import { disableDefaultPropsExceptForClasses, enableAsyncIterableChildren, disableStringRefs, + enableOwnerStacks, } from 'shared/ReactFeatureFlags'; import assign from 'shared/assign'; @@ -2372,6 +2373,27 @@ function renderNodeDestructive( key == null ? (childIndex === -1 ? 0 : childIndex) : key; const keyPath = [task.keyPath, name, keyOrIndex]; if (task.replay !== null) { + if (__DEV__ && enableOwnerStacks) { + const debugTask: null | ConsoleTask = element._debugTask; + if (debugTask) { + debugTask.run( + replayElement.bind( + null, + request, + task, + keyPath, + name, + keyOrIndex, + childIndex, + type, + props, + ref, + task.replay, + ), + ); + return; + } + } replayElement( request, task, @@ -2388,6 +2410,23 @@ function renderNodeDestructive( // prelude and skip it during the replay. } else { // We're doing a plain render. + if (__DEV__ && enableOwnerStacks) { + const debugTask: null | ConsoleTask = element._debugTask; + if (debugTask) { + debugTask.run( + renderElement.bind( + null, + request, + task, + keyPath, + type, + props, + ref, + ), + ); + return; + } + } renderElement(request, task, keyPath, type, props, ref); } return;