diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 072df8108fccd..fe23d642a8043 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -58,6 +58,8 @@ import { createStringDecoder, prepareDestinationForModule, bindToConsole, + rendererVersion, + rendererPackageName, } from './ReactFlightClientConfig'; import {createBoundServerReference} from './ReactFlightReplyClient'; @@ -76,6 +78,10 @@ import getComponentNameFromType from 'shared/getComponentNameFromType'; import {getOwnerStackByComponentInfoInDev} from 'shared/ReactComponentInfoStack'; +import {injectInternals} from './ReactFlightClientDevToolsHook'; + +import ReactVersion from 'shared/ReactVersion'; + import isArray from 'shared/isArray'; import * as React from 'react'; @@ -2921,3 +2927,21 @@ export function close(response: Response): void { // ref count of pending chunks. reportGlobalError(response, new Error('Connection closed.')); } + +function getCurrentOwnerInDEV(): null | ReactComponentInfo { + return currentOwnerInDEV; +} + +export function injectIntoDevTools(): boolean { + const internals: Object = { + bundleType: __DEV__ ? 1 : 0, // Might add PROFILE later. + version: rendererVersion, + rendererPackageName: rendererPackageName, + currentDispatcherRef: ReactSharedInternals, + // Enables DevTools to detect reconciler version rather than renderer version + // which may not match for third party renderers. + reconcilerVersion: ReactVersion, + getCurrentComponentInfo: getCurrentOwnerInDEV, + }; + return injectInternals(internals); +} diff --git a/packages/react-client/src/ReactFlightClientDevToolsHook.js b/packages/react-client/src/ReactFlightClientDevToolsHook.js new file mode 100644 index 0000000000000..b8ca649d4de45 --- /dev/null +++ b/packages/react-client/src/ReactFlightClientDevToolsHook.js @@ -0,0 +1,43 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +declare const __REACT_DEVTOOLS_GLOBAL_HOOK__: Object | void; + +export function injectInternals(internals: Object): boolean { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { + // No DevTools + return false; + } + const hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled) { + // This isn't a real property on the hook, but it can be set to opt out + // of DevTools integration and associated warnings and logs. + // https://github.com/facebook/react/issues/3877 + return true; + } + if (!hook.supportsFlight) { + // DevTools exists, even though it doesn't support Flight. + return true; + } + try { + hook.inject(internals); + } catch (err) { + // Catch all errors because it is unsafe to throw during initialization. + if (__DEV__) { + console.error('React instrumentation encountered an error: %s.', err); + } + } + if (hook.checkDCE) { + // This is the real DevTools. + return true; + } else { + // This is likely a hook installed by Fast Refresh runtime. + return false; + } +} diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.custom.js b/packages/react-client/src/forks/ReactFlightClientConfig.custom.js index d9b031c4b5fe1..530d548a590d0 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.custom.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.custom.js @@ -49,3 +49,6 @@ export const readPartialStringChunk = $$$config.readPartialStringChunk; export const readFinalStringChunk = $$$config.readFinalStringChunk; export const bindToConsole = $$$config.bindToConsole; + +export const rendererVersion = $$$config.rendererVersion; +export const rendererPackageName = $$$config.rendererPackageName; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-esm.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-esm.js index 55358ab05d10d..dbc89a2677d57 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-esm.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-esm.js @@ -7,6 +7,9 @@ * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'react-server-dom-esm'; + export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactClientConsoleConfigBrowser'; export * from 'react-server-dom-esm/src/client/ReactFlightClientConfigBundlerESM'; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-turbopack.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-turbopack.js index c3c511554ee6d..6a071981be9e7 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-turbopack.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-turbopack.js @@ -7,6 +7,9 @@ * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'react-server-dom-turbopack'; + export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactClientConsoleConfigBrowser'; export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack'; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser.js index 41bb93db386e8..73d27adefa847 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-browser.js @@ -7,6 +7,9 @@ * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'react-server-dom-webpack'; + export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactClientConsoleConfigBrowser'; export * from 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack'; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-bun.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-bun.js index 0a8027e3e12aa..7b75983cdd728 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-bun.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-bun.js @@ -7,6 +7,9 @@ * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'react-server-dom-bun'; + export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactClientConsoleConfigPlain'; export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM'; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-edge-turbopack.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-edge-turbopack.js index ac6d0933b7818..fbdb9fc683ac6 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-edge-turbopack.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-edge-turbopack.js @@ -7,6 +7,9 @@ * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'react-server-dom-turbopack'; + export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactClientConsoleConfigServer'; export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack'; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-edge-webpack.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-edge-webpack.js index eb17f259d3e19..f328a3e2ed7b1 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-edge-webpack.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-edge-webpack.js @@ -7,6 +7,9 @@ * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'react-server-dom-webpack'; + export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactClientConsoleConfigServer'; export * from 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack'; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-legacy.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-legacy.js index b992b01803260..05e937abdf82e 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-legacy.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-legacy.js @@ -7,6 +7,9 @@ * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'not-used'; + export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactClientConsoleConfigBrowser'; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-esm.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-esm.js index 9a17b9269a948..8cb512ea44aee 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-esm.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-esm.js @@ -7,6 +7,9 @@ * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'react-server-dom-esm'; + export * from 'react-client/src/ReactFlightClientStreamConfigNode'; export * from 'react-client/src/ReactClientConsoleConfigServer'; export * from 'react-server-dom-esm/src/client/ReactFlightClientConfigBundlerESM'; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack.js index f4226a93d86bc..ec97d45077b44 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack.js @@ -7,6 +7,9 @@ * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'react-server-dom-turbopack'; + export * from 'react-client/src/ReactFlightClientStreamConfigNode'; export * from 'react-client/src/ReactClientConsoleConfigServer'; export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack'; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-webpack.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-webpack.js index ccc12228d837f..9840d5bc911f7 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-webpack.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-webpack.js @@ -6,6 +6,8 @@ * * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'react-server-dom-webpack'; export * from 'react-client/src/ReactFlightClientStreamConfigNode'; export * from 'react-client/src/ReactClientConsoleConfigServer'; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node.js index 3425787b6434a..65e1252ee5b79 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node.js @@ -7,6 +7,9 @@ * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'react-server-dom-webpack'; + export * from 'react-client/src/ReactFlightClientStreamConfigNode'; export * from 'react-client/src/ReactClientConsoleConfigServer'; export * from 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerNode'; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.markup.js b/packages/react-client/src/forks/ReactFlightClientConfig.markup.js index a90acefccba39..ba86f7631ffce 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.markup.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.markup.js @@ -7,6 +7,9 @@ * @flow */ +export {default as rendererVersion} from 'shared/ReactVersion'; +export const rendererPackageName = 'react-markup'; + import type {Thenable} from 'shared/ReactTypes'; export * from 'react-markup/src/ReactMarkupLegacyClientStreamConfig.js'; diff --git a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js index 3abdac02e8c57..58a36e7023ca2 100644 --- a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js +++ b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js @@ -22,6 +22,7 @@ import { reportGlobalError, processBinaryChunk, close, + injectIntoDevTools, } from 'react-client/src/ReactFlightClient'; import { @@ -143,3 +144,7 @@ export { encodeReply, createServerReference, }; + +if (__DEV__) { + injectIntoDevTools(); +} diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js index 5a01a42417f7c..50a4a206ffb44 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js @@ -22,6 +22,7 @@ import { reportGlobalError, processBinaryChunk, close, + injectIntoDevTools, } from 'react-client/src/ReactFlightClient'; import { @@ -142,3 +143,7 @@ export { encodeReply, createServerReference, }; + +if (__DEV__) { + injectIntoDevTools(); +} diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js index 5a01a42417f7c..50a4a206ffb44 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js @@ -22,6 +22,7 @@ import { reportGlobalError, processBinaryChunk, close, + injectIntoDevTools, } from 'react-client/src/ReactFlightClient'; import { @@ -142,3 +143,7 @@ export { encodeReply, createServerReference, }; + +if (__DEV__) { + injectIntoDevTools(); +}