From 14e6ed731cbe891fcf02a005a7857d1faef83ec2 Mon Sep 17 00:00:00 2001 From: Emily Brown Date: Thu, 20 Nov 2025 13:17:37 +0000 Subject: [PATCH 1/8] Created checkbox for disabling the log dimming for the second invocation in strictmode --- .../views/Settings/DebuggingSettings.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js b/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js index 5dfce3a6dc2..2c0e55db47c 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js @@ -120,6 +120,27 @@ export default function DebuggingSettings({ + +
+ +
); } From bc81f09eaa9c469b2dfc62448cb88fffbaa0ca72 Mon Sep 17 00:00:00 2001 From: Emily Brown Date: Mon, 24 Nov 2025 12:53:48 +0000 Subject: [PATCH 2/8] Allow users to disable console dimming for second console logs in Strict mode --- .../src/__tests__/console-test.js | 81 +++++++++++++++++++ .../src/backend/types.js | 1 + .../views/Settings/DebuggingSettings.js | 14 ++-- packages/react-devtools-shared/src/hook.js | 28 ++++--- 4 files changed, 107 insertions(+), 17 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/console-test.js b/packages/react-devtools-shared/src/__tests__/console-test.js index 00d6d971267..c37285e855a 100644 --- a/packages/react-devtools-shared/src/__tests__/console-test.js +++ b/packages/react-devtools-shared/src/__tests__/console-test.js @@ -733,4 +733,85 @@ describe('console', () => { : 'in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', ]); }); + + it('should not dim console logs if disableSecondConsoleLogDimmingInStrictMode is enabled', () => { + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode = + false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.disableSecondConsoleLogDimmingInStrictMode = + true; + + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + + function App() { + console.log('log'); + console.warn('warn'); + console.error('error'); + return
; + } + + act(() => + root.render( + + + , + ), + ); + + // Both logs should be called (double logging) + expect(global.consoleLogMock).toHaveBeenCalledTimes(2); + expect(global.consoleWarnMock).toHaveBeenCalledTimes(2); + expect(global.consoleErrorMock).toHaveBeenCalledTimes(2); + + // The second log should NOT have dimming (no ANSI codes) + expect(global.consoleLogMock.mock.calls[1]).toEqual(['log']); + expect(global.consoleWarnMock.mock.calls[1]).toEqual(['warn']); + expect(global.consoleErrorMock.mock.calls[1]).toEqual(['error']); + }); + + it('should dim console logs if disableSecondConsoleLogDimmingInStrictMode is disabled', () => { + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode = + false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.disableSecondConsoleLogDimmingInStrictMode = + false; + + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + + function App() { + console.log('log'); + console.warn('warn'); + console.error('error'); + return
; + } + + act(() => + root.render( + + + , + ), + ); + + // Both logs should be called (double logging) + expect(global.consoleLogMock).toHaveBeenCalledTimes(2); + expect(global.consoleWarnMock).toHaveBeenCalledTimes(2); + expect(global.consoleErrorMock).toHaveBeenCalledTimes(2); + + // The second log should have dimming (ANSI codes present) + expect(global.consoleLogMock.mock.calls[1]).toEqual([ + '\x1b[2;38;2;124;124;124m%s\x1b[0m', + 'log', + ]); + expect(global.consoleWarnMock.mock.calls[1]).toEqual([ + '\x1b[2;38;2;124;124;124m%s\x1b[0m', + 'warn', + ]); + expect(global.consoleErrorMock.mock.calls[1]).toEqual([ + '\x1b[2;38;2;124;124;124m%s\x1b[0m', + 'error', + ]); + }); }); diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index 67d6a5f834b..00c66355b2d 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -597,4 +597,5 @@ export type DevToolsHookSettings = { breakOnConsoleErrors: boolean, showInlineWarningsAndErrors: boolean, hideConsoleLogsInStrictMode: boolean, + disableSecondConsoleLogDimmingInStrictMode: boolean, }; diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js b/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js index 2c0e55db47c..d68a3873a68 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js @@ -26,16 +26,16 @@ export default function DebuggingSettings({ }: Props): React.Node { const usedHookSettings = use(hookSettings); - const [appendComponentStack, setAppendComponentStack] = useState( - usedHookSettings.appendComponentStack, - ); - const [breakOnConsoleErrors, setBreakOnConsoleErrors] = useState( - usedHookSettings.breakOnConsoleErrors, - ); + const [appendComponentStack, setAppendComponentStack] = + useState(usedHookSettings.appendComponentStack); + const [breakOnConsoleErrors, setBreakOnConsoleErrors] = + useState(usedHookSettings.breakOnConsoleErrors,); const [hideConsoleLogsInStrictMode, setHideConsoleLogsInStrictMode] = useState(usedHookSettings.hideConsoleLogsInStrictMode); const [showInlineWarningsAndErrors, setShowInlineWarningsAndErrors] = useState(usedHookSettings.showInlineWarningsAndErrors); + const [disableSecondConsoleLogDimmingInStrictMode, setDisableSecondConsoleLogDimmingInStrictMode] = + useState(usedHookSettings.disableSecondConsoleLogDimmingInStrictMode); useEffect(() => { store.setShouldShowWarningsAndErrors(showInlineWarningsAndErrors); @@ -47,6 +47,7 @@ export default function DebuggingSettings({ breakOnConsoleErrors, showInlineWarningsAndErrors, hideConsoleLogsInStrictMode, + disableSecondConsoleLogDimmingInStrictMode, }); }, [ store, @@ -54,6 +55,7 @@ export default function DebuggingSettings({ breakOnConsoleErrors, showInlineWarningsAndErrors, hideConsoleLogsInStrictMode, + disableSecondConsoleLogDimmingInStrictMode, ]); return ( diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index 699d2309457..d7522f22525 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -367,17 +367,22 @@ export function installHook( return; } - // Dim the text color of the double logs if we're not hiding them. - // Firefox doesn't support ANSI escape sequences - if (__IS_FIREFOX__) { - originalMethod( - ...formatWithStyles(args, FIREFOX_CONSOLE_DIMMING_COLOR), - ); + if (settings.disableSecondConsoleLogDimmingInStrictMode) { + // Don't dim the console logs + originalMethod(...args); } else { - originalMethod( - ANSI_STYLE_DIMMING_TEMPLATE, - ...formatConsoleArguments(...args), - ); + // Dim the text color of the double logs if we're not hiding them. + // Firefox doesn't support ANSI escape sequences + if (__IS_FIREFOX__) { + originalMethod( + ...formatWithStyles(args, FIREFOX_CONSOLE_DIMMING_COLOR), + ); + } else { + originalMethod( + ANSI_STYLE_DIMMING_TEMPLATE, + ...formatConsoleArguments(...args), + ); + } } }; @@ -579,7 +584,7 @@ export function installHook( debugger; } - if (isRunningDuringStrictModeInvocation) { + if (isRunningDuringStrictModeInvocation && !settings.disableSecondConsoleLogDimmingInStrictMode) { // Dim the text color of the double logs if we're not hiding them. // Firefox doesn't support ANSI escape sequences if (__IS_FIREFOX__) { @@ -667,6 +672,7 @@ export function installHook( breakOnConsoleErrors: false, showInlineWarningsAndErrors: true, hideConsoleLogsInStrictMode: false, + disableSecondConsoleLogDimmingInStrictMode: false, }; patchConsoleForErrorsAndWarnings(); } else { From a911b0f671ea3143ae3ddcf1afb8f07986c0e6ec Mon Sep 17 00:00:00 2001 From: Emily Brown Date: Mon, 24 Nov 2025 15:46:27 +0000 Subject: [PATCH 3/8] Cannot undim strict mode duplicate logs when they are hidden --- .../contentScripts/hookSettingsInjector.js | 5 +++ .../views/Settings/DebuggingSettings.js | 44 ++++++++++++++----- .../views/Settings/SettingsShared.css | 5 +++ packages/react-devtools-shared/src/hook.js | 5 ++- 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/packages/react-devtools-extensions/src/contentScripts/hookSettingsInjector.js b/packages/react-devtools-extensions/src/contentScripts/hookSettingsInjector.js index e26108edac7..da809f65cac 100644 --- a/packages/react-devtools-extensions/src/contentScripts/hookSettingsInjector.js +++ b/packages/react-devtools-extensions/src/contentScripts/hookSettingsInjector.js @@ -24,6 +24,11 @@ async function messageListener(event: MessageEvent) { if (typeof settings.hideConsoleLogsInStrictMode !== 'boolean') { settings.hideConsoleLogsInStrictMode = false; } + if ( + typeof settings.disableSecondConsoleLogDimmingInStrictMode !== 'boolean' + ) { + settings.disableSecondConsoleLogDimmingInStrictMode = false; + } window.postMessage({ source: 'react-devtools-hook-settings-injector', diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js b/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js index d68a3873a68..34b08c5bfcd 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js @@ -26,16 +26,20 @@ export default function DebuggingSettings({ }: Props): React.Node { const usedHookSettings = use(hookSettings); - const [appendComponentStack, setAppendComponentStack] = - useState(usedHookSettings.appendComponentStack); - const [breakOnConsoleErrors, setBreakOnConsoleErrors] = - useState(usedHookSettings.breakOnConsoleErrors,); + const [appendComponentStack, setAppendComponentStack] = useState( + usedHookSettings.appendComponentStack, + ); + const [breakOnConsoleErrors, setBreakOnConsoleErrors] = useState( + usedHookSettings.breakOnConsoleErrors, + ); const [hideConsoleLogsInStrictMode, setHideConsoleLogsInStrictMode] = useState(usedHookSettings.hideConsoleLogsInStrictMode); const [showInlineWarningsAndErrors, setShowInlineWarningsAndErrors] = useState(usedHookSettings.showInlineWarningsAndErrors); - const [disableSecondConsoleLogDimmingInStrictMode, setDisableSecondConsoleLogDimmingInStrictMode] = - useState(usedHookSettings.disableSecondConsoleLogDimmingInStrictMode); + const [ + disableSecondConsoleLogDimmingInStrictMode, + setDisableSecondConsoleLogDimmingInStrictMode, + ] = useState(usedHookSettings.disableSecondConsoleLogDimmingInStrictMode); useEffect(() => { store.setShouldShowWarningsAndErrors(showInlineWarningsAndErrors); @@ -107,9 +111,12 @@ export default function DebuggingSettings({ - setHideConsoleLogsInStrictMode(currentTarget.checked) - } + onChange={({currentTarget}) => { + setHideConsoleLogsInStrictMode(currentTarget.checked); + if (currentTarget.checked) { + setDisableSecondConsoleLogDimmingInStrictMode(false); + } + }} className={styles.SettingRowCheckbox} /> Hide logs during additional invocations in  @@ -123,13 +130,26 @@ export default function DebuggingSettings({
-
-