diff --git a/packages/react-devtools-shared/src/backend/DevToolsFiberComponentStack.js b/packages/react-devtools-shared/src/backend/DevToolsFiberComponentStack.js index 6d99cf4f21e52..a4311797de36c 100644 --- a/packages/react-devtools-shared/src/backend/DevToolsFiberComponentStack.js +++ b/packages/react-devtools-shared/src/backend/DevToolsFiberComponentStack.js @@ -98,3 +98,10 @@ export function getStackByFiberInDevAndProd( return '\nError generating stack: ' + x.message + '\n' + x.stack; } } + +export function supportsNativeConsoleTasks(fiber: Fiber): boolean { + // If this Fiber supports native console.createTask then we are already running + // inside a native async stack trace if it's active - meaning the DevTools is open. + // Ideally we'd detect if this task was created while the DevTools was open or not. + return !!fiber._debugTask; +} diff --git a/packages/react-devtools-shared/src/backend/console.js b/packages/react-devtools-shared/src/backend/console.js index 40649abe9ee46..13c2249013a3e 100644 --- a/packages/react-devtools-shared/src/backend/console.js +++ b/packages/react-devtools-shared/src/backend/console.js @@ -18,7 +18,10 @@ import type { import {format, formatWithStyles} from './utils'; import {getInternalReactConstants, getDispatcherRef} from './renderer'; -import {getStackByFiberInDevAndProd} from './DevToolsFiberComponentStack'; +import { + getStackByFiberInDevAndProd, + supportsNativeConsoleTasks, +} from './DevToolsFiberComponentStack'; import {consoleManagedByDevToolsDuringStrictMode} from 'react-devtools-feature-flags'; import {castBool, castBrowserTheme} from '../utils'; @@ -235,7 +238,10 @@ export function patch({ } } - if (shouldAppendWarningStack) { + if ( + shouldAppendWarningStack && + !supportsNativeConsoleTasks(current) + ) { const componentStack = getStackByFiberInDevAndProd( workTagMap, current, diff --git a/packages/react-reconciler/src/ReactCurrentFiber.js b/packages/react-reconciler/src/ReactCurrentFiber.js index 98e82247d5893..cf0c2543a574f 100644 --- a/packages/react-reconciler/src/ReactCurrentFiber.js +++ b/packages/react-reconciler/src/ReactCurrentFiber.js @@ -74,6 +74,13 @@ export function runWithFiberInDEV( const previousFiber = current; setCurrentFiber(fiber); try { + if (enableOwnerStacks) { + if (fiber !== null && fiber._debugTask) { + return fiber._debugTask.run( + callback.bind(null, arg0, arg1, arg2, arg3, arg4), + ); + } + } return callback(arg0, arg1, arg2, arg3, arg4); } finally { current = previousFiber; diff --git a/packages/shared/consoleWithStackDev.js b/packages/shared/consoleWithStackDev.js index 464f1b09992f0..bdcf7548021b5 100644 --- a/packages/shared/consoleWithStackDev.js +++ b/packages/shared/consoleWithStackDev.js @@ -6,6 +6,7 @@ */ import ReactSharedInternals from 'shared/ReactSharedInternals'; +import {enableOwnerStacks} from 'shared/ReactFeatureFlags'; let suppressWarning = false; export function setSuppressWarning(newSuppressWarning) { @@ -36,6 +37,9 @@ export function error(format, ...args) { } } +// eslint-disable-next-line react-internal/no-production-logging +const supportsCreateTask = __DEV__ && enableOwnerStacks && !!console.createTask; + function printWarning(level, format, args) { // When changing this logic, you might want to also // update consoleWithStackDev.www.js as well. @@ -43,7 +47,10 @@ function printWarning(level, format, args) { const isErrorLogger = format === '%s\n\n%s\n' || format === '%o\n\n%s\n\n%s\n'; - if (ReactSharedInternals.getCurrentStack) { + if (!supportsCreateTask && ReactSharedInternals.getCurrentStack) { + // We only add the current stack to the console when createTask is not supported. + // Since createTask requires DevTools to be open to work, this means that stacks + // can be lost while DevTools isn't open but we can't detect this. const stack = ReactSharedInternals.getCurrentStack(); if (stack !== '') { format += '%s';