From 4ce3b9a1f333de83a1f00409028ea3735d2a0db5 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Tue, 11 Jun 2024 15:21:52 +0100 Subject: [PATCH 1/4] chore[react-devtools/backend]: remove consoleManagedByDevToolsDuringStrictMode flag --- .../src/backend/console.js | 111 +++++++++--------- .../config/DevToolsFeatureFlags.core-fb.js | 1 - .../config/DevToolsFeatureFlags.core-oss.js | 1 - .../config/DevToolsFeatureFlags.default.js | 1 - .../DevToolsFeatureFlags.extension-fb.js | 1 - .../DevToolsFeatureFlags.extension-oss.js | 1 - 6 files changed, 53 insertions(+), 63 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/console.js b/packages/react-devtools-shared/src/backend/console.js index 13c2249013a3e..0aa0bcdbff8db 100644 --- a/packages/react-devtools-shared/src/backend/console.js +++ b/packages/react-devtools-shared/src/backend/console.js @@ -22,7 +22,6 @@ import { getStackByFiberInDevAndProd, supportsNativeConsoleTasks, } from './DevToolsFiberComponentStack'; -import {consoleManagedByDevToolsDuringStrictMode} from 'react-devtools-feature-flags'; import {castBool, castBrowserTheme} from '../utils'; const OVERRIDE_CONSOLE_METHODS = ['error', 'trace', 'warn']; @@ -302,76 +301,72 @@ let unpatchForStrictModeFn: null | (() => void) = null; // NOTE: KEEP IN SYNC with src/hook.js:patchConsoleForInitialCommitInStrictMode export function patchForStrictMode() { - if (consoleManagedByDevToolsDuringStrictMode) { - const overrideConsoleMethods = [ - 'error', - 'group', - 'groupCollapsed', - 'info', - 'log', - 'trace', - 'warn', - ]; - - if (unpatchForStrictModeFn !== null) { - // Don't patch twice. - return; - } + const overrideConsoleMethods = [ + 'error', + 'group', + 'groupCollapsed', + 'info', + 'log', + 'trace', + 'warn', + ]; + + if (unpatchForStrictModeFn !== null) { + // Don't patch twice. + return; + } - const originalConsoleMethods: {[string]: $FlowFixMe} = {}; + const originalConsoleMethods: {[string]: $FlowFixMe} = {}; - unpatchForStrictModeFn = () => { - for (const method in originalConsoleMethods) { - try { - targetConsole[method] = originalConsoleMethods[method]; - } catch (error) {} - } - }; - - overrideConsoleMethods.forEach(method => { + unpatchForStrictModeFn = () => { + for (const method in originalConsoleMethods) { try { - const originalMethod = (originalConsoleMethods[method] = targetConsole[ - method - ].__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ - ? targetConsole[method].__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ - : targetConsole[method]); + targetConsole[method] = originalConsoleMethods[method]; + } catch (error) {} + } + }; - // $FlowFixMe[missing-local-annot] - const overrideMethod = (...args) => { - if (!consoleSettingsRef.hideConsoleLogsInStrictMode) { - // Dim the text color of the double logs if we're not - // hiding them. - if (isNode) { - originalMethod(DIMMED_NODE_CONSOLE_COLOR, format(...args)); + overrideConsoleMethods.forEach(method => { + try { + const originalMethod = (originalConsoleMethods[method] = targetConsole[ + method + ].__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ + ? targetConsole[method].__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ + : targetConsole[method]); + + // $FlowFixMe[missing-local-annot] + const overrideMethod = (...args) => { + if (!consoleSettingsRef.hideConsoleLogsInStrictMode) { + // Dim the text color of the double logs if we're not + // hiding them. + if (isNode) { + originalMethod(DIMMED_NODE_CONSOLE_COLOR, format(...args)); + } else { + const color = getConsoleColor(method); + if (color) { + originalMethod(...formatWithStyles(args, `color: ${color}`)); } else { - const color = getConsoleColor(method); - if (color) { - originalMethod(...formatWithStyles(args, `color: ${color}`)); - } else { - throw Error('Console color is not defined'); - } + throw Error('Console color is not defined'); } } - }; + } + }; - overrideMethod.__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ = - originalMethod; - originalMethod.__REACT_DEVTOOLS_STRICT_MODE_OVERRIDE_METHOD__ = - overrideMethod; + overrideMethod.__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ = + originalMethod; + originalMethod.__REACT_DEVTOOLS_STRICT_MODE_OVERRIDE_METHOD__ = + overrideMethod; - targetConsole[method] = overrideMethod; - } catch (error) {} - }); - } + targetConsole[method] = overrideMethod; + } catch (error) {} + }); } // NOTE: KEEP IN SYNC with src/hook.js:unpatchConsoleForInitialCommitInStrictMode export function unpatchForStrictMode(): void { - if (consoleManagedByDevToolsDuringStrictMode) { - if (unpatchForStrictModeFn !== null) { - unpatchForStrictModeFn(); - unpatchForStrictModeFn = null; - } + if (unpatchForStrictModeFn !== null) { + unpatchForStrictModeFn(); + unpatchForStrictModeFn = null; } } diff --git a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.core-fb.js b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.core-fb.js index 9c29e361fae91..47e15953c9780 100644 --- a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.core-fb.js +++ b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.core-fb.js @@ -13,7 +13,6 @@ * It should always be imported from "react-devtools-feature-flags". ************************************************************************/ -export const consoleManagedByDevToolsDuringStrictMode = false; export const enableLogger = true; export const enableStyleXFeatures = true; export const isInternalFacebookBuild = true; diff --git a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.core-oss.js b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.core-oss.js index 060e5e808ede2..e7ec62243adef 100644 --- a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.core-oss.js +++ b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.core-oss.js @@ -13,7 +13,6 @@ * It should always be imported from "react-devtools-feature-flags". ************************************************************************/ -export const consoleManagedByDevToolsDuringStrictMode = false; export const enableLogger = false; export const enableStyleXFeatures = false; export const isInternalFacebookBuild = false; diff --git a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js index 15b764f8d352b..bba2c8fcbfb05 100644 --- a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js +++ b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js @@ -13,7 +13,6 @@ * It should always be imported from "react-devtools-feature-flags". ************************************************************************/ -export const consoleManagedByDevToolsDuringStrictMode = true; export const enableLogger = false; export const enableStyleXFeatures = false; export const isInternalFacebookBuild = false; diff --git a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-fb.js b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-fb.js index b25db375eff29..55ea045715013 100644 --- a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-fb.js +++ b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-fb.js @@ -13,7 +13,6 @@ * It should always be imported from "react-devtools-feature-flags". ************************************************************************/ -export const consoleManagedByDevToolsDuringStrictMode = true; export const enableLogger = true; export const enableStyleXFeatures = true; export const isInternalFacebookBuild = true; diff --git a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-oss.js b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-oss.js index 144ddb301f848..75c8f149b3814 100644 --- a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-oss.js +++ b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-oss.js @@ -13,7 +13,6 @@ * It should always be imported from "react-devtools-feature-flags". ************************************************************************/ -export const consoleManagedByDevToolsDuringStrictMode = true; export const enableLogger = false; export const enableStyleXFeatures = false; export const isInternalFacebookBuild = false; From b5b106b66d6daadab35244f3133586a2081b9032 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Tue, 11 Jun 2024 23:02:07 +0100 Subject: [PATCH 2/4] chore[react-devtools]: unify console patching and default to ansi escape symbols --- .eslintrc.js | 6 +- .../react-devtools-core/webpack.backend.js | 13 +- .../react-devtools-core/webpack.standalone.js | 12 -- packages/react-devtools-extensions/utils.js | 13 -- .../webpack.backend.js | 17 +- .../webpack.config.js | 17 +- .../webpack.config.frontend.js | 12 -- .../react-devtools-inline/webpack.config.js | 12 -- .../src/__tests__/console-test.js | 165 ++++++------------ .../src/backend/console.js | 74 ++++---- .../react-devtools-shared/src/constants.js | 19 +- packages/react-devtools-shared/src/hook.js | 55 ++---- .../react-devtools-shell/webpack-server.js | 12 -- scripts/flow/react-devtools.js | 7 +- scripts/jest/devtools/setupEnv.js | 20 +-- 15 files changed, 113 insertions(+), 341 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index ec20e2196e94b..fb2fdf0d5e9a1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -451,7 +451,11 @@ module.exports = { }, }, { - files: ['packages/react-devtools-extensions/**/*.js'], + files: [ + 'packages/react-devtools-extensions/**/*.js', + 'packages/react-devtools-shared/src/hook.js', + 'packages/react-devtools-shared/src/backend/console.js', + ], globals: { __IS_CHROME__: 'readonly', __IS_FIREFOX__: 'readonly', diff --git a/packages/react-devtools-core/webpack.backend.js b/packages/react-devtools-core/webpack.backend.js index 67bf81d0f9965..24e3ced0d7b46 100644 --- a/packages/react-devtools-core/webpack.backend.js +++ b/packages/react-devtools-core/webpack.backend.js @@ -1,12 +1,6 @@ const {resolve} = require('path'); const Webpack = require('webpack'); const { - DARK_MODE_DIMMED_WARNING_COLOR, - DARK_MODE_DIMMED_ERROR_COLOR, - DARK_MODE_DIMMED_LOG_COLOR, - LIGHT_MODE_DIMMED_WARNING_COLOR, - LIGHT_MODE_DIMMED_ERROR_COLOR, - LIGHT_MODE_DIMMED_LOG_COLOR, GITHUB_URL, getVersionString, } = require('react-devtools-extensions/utils'); @@ -74,15 +68,10 @@ module.exports = { __EXTENSION__: false, __PROFILE__: false, __TEST__: NODE_ENV === 'test', + __IS_FIREFOX__: false, 'process.env.DEVTOOLS_PACKAGE': `"react-devtools-core"`, 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, - 'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_ERROR_COLOR': `"${DARK_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_LOG_COLOR': `"${DARK_MODE_DIMMED_LOG_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_WARNING_COLOR': `"${LIGHT_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_ERROR_COLOR': `"${LIGHT_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_LOG_COLOR': `"${LIGHT_MODE_DIMMED_LOG_COLOR}"`, }), ], optimization: { diff --git a/packages/react-devtools-core/webpack.standalone.js b/packages/react-devtools-core/webpack.standalone.js index fd37617761752..5995876e41de5 100644 --- a/packages/react-devtools-core/webpack.standalone.js +++ b/packages/react-devtools-core/webpack.standalone.js @@ -1,12 +1,6 @@ const {resolve} = require('path'); const Webpack = require('webpack'); const { - DARK_MODE_DIMMED_WARNING_COLOR, - DARK_MODE_DIMMED_ERROR_COLOR, - DARK_MODE_DIMMED_LOG_COLOR, - LIGHT_MODE_DIMMED_WARNING_COLOR, - LIGHT_MODE_DIMMED_ERROR_COLOR, - LIGHT_MODE_DIMMED_LOG_COLOR, GITHUB_URL, getVersionString, } = require('react-devtools-extensions/utils'); @@ -99,12 +93,6 @@ module.exports = { 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, 'process.env.LOGGING_URL': `"${LOGGING_URL}"`, 'process.env.NODE_ENV': `"${NODE_ENV}"`, - 'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_ERROR_COLOR': `"${DARK_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_LOG_COLOR': `"${DARK_MODE_DIMMED_LOG_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_WARNING_COLOR': `"${LIGHT_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_ERROR_COLOR': `"${LIGHT_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_LOG_COLOR': `"${LIGHT_MODE_DIMMED_LOG_COLOR}"`, }), ], module: { diff --git a/packages/react-devtools-extensions/utils.js b/packages/react-devtools-extensions/utils.js index 95a72a37ae340..3b06bb71f7d4e 100644 --- a/packages/react-devtools-extensions/utils.js +++ b/packages/react-devtools-extensions/utils.js @@ -9,13 +9,6 @@ const {execSync} = require('child_process'); const {readFileSync} = require('fs'); const {resolve} = require('path'); -const DARK_MODE_DIMMED_WARNING_COLOR = 'rgba(250, 180, 50, 0.5)'; -const DARK_MODE_DIMMED_ERROR_COLOR = 'rgba(250, 123, 130, 0.5)'; -const DARK_MODE_DIMMED_LOG_COLOR = 'rgba(125, 125, 125, 0.5)'; -const LIGHT_MODE_DIMMED_WARNING_COLOR = 'rgba(250, 180, 50, 0.75)'; -const LIGHT_MODE_DIMMED_ERROR_COLOR = 'rgba(250, 123, 130, 0.75)'; -const LIGHT_MODE_DIMMED_LOG_COLOR = 'rgba(125, 125, 125, 0.75)'; - const GITHUB_URL = 'https://github.com/facebook/react'; function getGitCommit() { @@ -45,12 +38,6 @@ function getVersionString(packageVersion = null) { } module.exports = { - DARK_MODE_DIMMED_WARNING_COLOR, - DARK_MODE_DIMMED_ERROR_COLOR, - DARK_MODE_DIMMED_LOG_COLOR, - LIGHT_MODE_DIMMED_WARNING_COLOR, - LIGHT_MODE_DIMMED_ERROR_COLOR, - LIGHT_MODE_DIMMED_LOG_COLOR, GITHUB_URL, getGitCommit, getVersionString, diff --git a/packages/react-devtools-extensions/webpack.backend.js b/packages/react-devtools-extensions/webpack.backend.js index 33b30247c7804..8cc32f8f93ccc 100644 --- a/packages/react-devtools-extensions/webpack.backend.js +++ b/packages/react-devtools-extensions/webpack.backend.js @@ -6,16 +6,7 @@ const Webpack = require('webpack'); const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils'); const SourceMapIgnoreListPlugin = require('react-devtools-shared/SourceMapIgnoreListPlugin'); -const { - DARK_MODE_DIMMED_WARNING_COLOR, - DARK_MODE_DIMMED_ERROR_COLOR, - DARK_MODE_DIMMED_LOG_COLOR, - LIGHT_MODE_DIMMED_WARNING_COLOR, - LIGHT_MODE_DIMMED_ERROR_COLOR, - LIGHT_MODE_DIMMED_LOG_COLOR, - GITHUB_URL, - getVersionString, -} = require('./utils'); +const {GITHUB_URL, getVersionString} = require('./utils'); const NODE_ENV = process.env.NODE_ENV; if (!NODE_ENV) { @@ -80,12 +71,6 @@ module.exports = { 'process.env.DEVTOOLS_PACKAGE': `"react-devtools-extensions"`, 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, - 'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_ERROR_COLOR': `"${DARK_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_LOG_COLOR': `"${DARK_MODE_DIMMED_LOG_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_WARNING_COLOR': `"${LIGHT_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_ERROR_COLOR': `"${LIGHT_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_LOG_COLOR': `"${LIGHT_MODE_DIMMED_LOG_COLOR}"`, 'process.env.IS_CHROME': IS_CHROME, 'process.env.IS_FIREFOX': IS_FIREFOX, 'process.env.IS_EDGE': IS_EDGE, diff --git a/packages/react-devtools-extensions/webpack.config.js b/packages/react-devtools-extensions/webpack.config.js index 4195a43abfe58..b91cd07baf018 100644 --- a/packages/react-devtools-extensions/webpack.config.js +++ b/packages/react-devtools-extensions/webpack.config.js @@ -3,16 +3,7 @@ const {resolve} = require('path'); const Webpack = require('webpack'); const TerserPlugin = require('terser-webpack-plugin'); -const { - DARK_MODE_DIMMED_WARNING_COLOR, - DARK_MODE_DIMMED_ERROR_COLOR, - DARK_MODE_DIMMED_LOG_COLOR, - LIGHT_MODE_DIMMED_WARNING_COLOR, - LIGHT_MODE_DIMMED_ERROR_COLOR, - LIGHT_MODE_DIMMED_LOG_COLOR, - GITHUB_URL, - getVersionString, -} = require('./utils'); +const {GITHUB_URL, getVersionString} = require('./utils'); const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils'); const SourceMapIgnoreListPlugin = require('react-devtools-shared/SourceMapIgnoreListPlugin'); @@ -128,12 +119,6 @@ module.exports = { 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, 'process.env.LOGGING_URL': `"${LOGGING_URL}"`, 'process.env.NODE_ENV': `"${NODE_ENV}"`, - 'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_ERROR_COLOR': `"${DARK_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_LOG_COLOR': `"${DARK_MODE_DIMMED_LOG_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_WARNING_COLOR': `"${LIGHT_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_ERROR_COLOR': `"${LIGHT_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_LOG_COLOR': `"${LIGHT_MODE_DIMMED_LOG_COLOR}"`, }), new Webpack.SourceMapDevToolPlugin({ filename: '[file].map', diff --git a/packages/react-devtools-fusebox/webpack.config.frontend.js b/packages/react-devtools-fusebox/webpack.config.frontend.js index 713362e04e42d..40487f623bed7 100644 --- a/packages/react-devtools-fusebox/webpack.config.frontend.js +++ b/packages/react-devtools-fusebox/webpack.config.frontend.js @@ -1,12 +1,6 @@ const {resolve} = require('path'); const Webpack = require('webpack'); const { - DARK_MODE_DIMMED_WARNING_COLOR, - DARK_MODE_DIMMED_ERROR_COLOR, - DARK_MODE_DIMMED_LOG_COLOR, - LIGHT_MODE_DIMMED_WARNING_COLOR, - LIGHT_MODE_DIMMED_ERROR_COLOR, - LIGHT_MODE_DIMMED_LOG_COLOR, GITHUB_URL, getVersionString, } = require('react-devtools-extensions/utils'); @@ -93,12 +87,6 @@ module.exports = { 'process.env.EDITOR_URL': EDITOR_URL != null ? `"${EDITOR_URL}"` : null, 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, 'process.env.NODE_ENV': `"${NODE_ENV}"`, - 'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_ERROR_COLOR': `"${DARK_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_LOG_COLOR': `"${DARK_MODE_DIMMED_LOG_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_WARNING_COLOR': `"${LIGHT_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_ERROR_COLOR': `"${LIGHT_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_LOG_COLOR': `"${LIGHT_MODE_DIMMED_LOG_COLOR}"`, }), ], module: { diff --git a/packages/react-devtools-inline/webpack.config.js b/packages/react-devtools-inline/webpack.config.js index ca785f773f27d..2ab8db739a599 100644 --- a/packages/react-devtools-inline/webpack.config.js +++ b/packages/react-devtools-inline/webpack.config.js @@ -1,12 +1,6 @@ const {resolve} = require('path'); const Webpack = require('webpack'); const { - DARK_MODE_DIMMED_WARNING_COLOR, - DARK_MODE_DIMMED_ERROR_COLOR, - DARK_MODE_DIMMED_LOG_COLOR, - LIGHT_MODE_DIMMED_WARNING_COLOR, - LIGHT_MODE_DIMMED_ERROR_COLOR, - LIGHT_MODE_DIMMED_LOG_COLOR, GITHUB_URL, getVersionString, } = require('react-devtools-extensions/utils'); @@ -84,12 +78,6 @@ module.exports = { 'process.env.EDITOR_URL': EDITOR_URL != null ? `"${EDITOR_URL}"` : null, 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, 'process.env.NODE_ENV': `"${NODE_ENV}"`, - 'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_ERROR_COLOR': `"${DARK_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_LOG_COLOR': `"${DARK_MODE_DIMMED_LOG_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_WARNING_COLOR': `"${LIGHT_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_ERROR_COLOR': `"${LIGHT_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_LOG_COLOR': `"${LIGHT_MODE_DIMMED_LOG_COLOR}"`, }), ], module: { diff --git a/packages/react-devtools-shared/src/__tests__/console-test.js b/packages/react-devtools-shared/src/__tests__/console-test.js index e7a60ea369560..c79850901a825 100644 --- a/packages/react-devtools-shared/src/__tests__/console-test.js +++ b/packages/react-devtools-shared/src/__tests__/console-test.js @@ -515,58 +515,52 @@ describe('console', () => { expect(mockLog.mock.calls[0]).toHaveLength(1); expect(mockLog.mock.calls[0][0]).toBe('log'); expect(mockLog.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log', ]); expect(mockWarn).toHaveBeenCalledTimes(2); expect(mockWarn.mock.calls[0]).toHaveLength(1); expect(mockWarn.mock.calls[0][0]).toBe('warn'); - expect(mockWarn.mock.calls[1]).toHaveLength(3); + expect(mockWarn.mock.calls[1]).toHaveLength(2); expect(mockWarn.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_WARNING_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn', ]); expect(mockError).toHaveBeenCalledTimes(2); expect(mockError.mock.calls[0]).toHaveLength(1); expect(mockError.mock.calls[0][0]).toBe('error'); - expect(mockError.mock.calls[1]).toHaveLength(3); + expect(mockError.mock.calls[1]).toHaveLength(2); expect(mockError.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_ERROR_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error', ]); expect(mockInfo).toHaveBeenCalledTimes(2); expect(mockInfo.mock.calls[0]).toHaveLength(1); expect(mockInfo.mock.calls[0][0]).toBe('info'); - expect(mockInfo.mock.calls[1]).toHaveLength(3); + expect(mockInfo.mock.calls[1]).toHaveLength(2); expect(mockInfo.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'info', ]); expect(mockGroup).toHaveBeenCalledTimes(2); expect(mockGroup.mock.calls[0]).toHaveLength(1); expect(mockGroup.mock.calls[0][0]).toBe('group'); - expect(mockGroup.mock.calls[1]).toHaveLength(3); + expect(mockGroup.mock.calls[1]).toHaveLength(2); expect(mockGroup.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'group', ]); expect(mockGroupCollapsed).toHaveBeenCalledTimes(2); expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1); expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed'); - expect(mockGroupCollapsed.mock.calls[1]).toHaveLength(3); + expect(mockGroupCollapsed.mock.calls[1]).toHaveLength(2); expect(mockGroupCollapsed.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'groupCollapsed', ]); }); @@ -663,81 +657,33 @@ describe('console', () => { ); expect(mockLog.mock.calls).toEqual([ ['log effect create'], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, - 'log effect cleanup', - ], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, - 'log effect create', - ], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log effect cleanup'], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log effect create'], ]); expect(mockWarn.mock.calls).toEqual([ ['warn effect create'], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_WARNING_COLOR}`, - 'warn effect cleanup', - ], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_WARNING_COLOR}`, - 'warn effect create', - ], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn effect cleanup'], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn effect create'], ]); expect(mockError.mock.calls).toEqual([ ['error effect create'], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_ERROR_COLOR}`, - 'error effect cleanup', - ], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_ERROR_COLOR}`, - 'error effect create', - ], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error effect cleanup'], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error effect create'], ]); expect(mockInfo.mock.calls).toEqual([ ['info effect create'], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, - 'info effect cleanup', - ], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, - 'info effect create', - ], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'info effect cleanup'], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'info effect create'], ]); expect(mockGroup.mock.calls).toEqual([ ['group effect create'], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, - 'group effect cleanup', - ], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, - 'group effect create', - ], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'group effect cleanup'], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'group effect create'], ]); expect(mockGroupCollapsed.mock.calls).toEqual([ ['groupCollapsed effect create'], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, - 'groupCollapsed effect cleanup', - ], - [ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, - 'groupCollapsed effect create', - ], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'groupCollapsed effect cleanup'], + ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'groupCollapsed effect create'], ]); }); @@ -816,58 +762,52 @@ describe('console', () => { expect(mockLog.mock.calls[0]).toHaveLength(1); expect(mockLog.mock.calls[0][0]).toBe('log'); expect(mockLog.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log', ]); expect(mockWarn).toHaveBeenCalledTimes(2); expect(mockWarn.mock.calls[0]).toHaveLength(1); expect(mockWarn.mock.calls[0][0]).toBe('warn'); - expect(mockWarn.mock.calls[1]).toHaveLength(3); + expect(mockWarn.mock.calls[1]).toHaveLength(2); expect(mockWarn.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_WARNING_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn', ]); expect(mockError).toHaveBeenCalledTimes(2); expect(mockError.mock.calls[0]).toHaveLength(1); expect(mockError.mock.calls[0][0]).toBe('error'); - expect(mockError.mock.calls[1]).toHaveLength(3); + expect(mockError.mock.calls[1]).toHaveLength(2); expect(mockError.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_ERROR_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error', ]); expect(mockInfo).toHaveBeenCalledTimes(2); expect(mockInfo.mock.calls[0]).toHaveLength(1); expect(mockInfo.mock.calls[0][0]).toBe('info'); - expect(mockInfo.mock.calls[1]).toHaveLength(3); + expect(mockInfo.mock.calls[1]).toHaveLength(2); expect(mockInfo.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'info', ]); expect(mockGroup).toHaveBeenCalledTimes(2); expect(mockGroup.mock.calls[0]).toHaveLength(1); expect(mockGroup.mock.calls[0][0]).toBe('group'); - expect(mockGroup.mock.calls[1]).toHaveLength(3); + expect(mockGroup.mock.calls[1]).toHaveLength(2); expect(mockGroup.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'group', ]); expect(mockGroupCollapsed).toHaveBeenCalledTimes(2); expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1); expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed'); - expect(mockGroupCollapsed.mock.calls[1]).toHaveLength(3); + expect(mockGroupCollapsed.mock.calls[1]).toHaveLength(2); expect(mockGroupCollapsed.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'groupCollapsed', ]); }); @@ -960,30 +900,27 @@ describe('console', () => { expect(mockLog).toHaveBeenCalledTimes(2); expect(mockLog.mock.calls[0]).toHaveLength(1); expect(mockLog.mock.calls[0][0]).toBe('log'); - expect(mockLog.mock.calls[1]).toHaveLength(3); + expect(mockLog.mock.calls[1]).toHaveLength(2); expect(mockLog.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log', ]); expect(mockWarn).toHaveBeenCalledTimes(2); expect(mockWarn.mock.calls[0]).toHaveLength(1); expect(mockWarn.mock.calls[0][0]).toBe('warn'); - expect(mockWarn.mock.calls[1]).toHaveLength(3); + expect(mockWarn.mock.calls[1]).toHaveLength(2); expect(mockWarn.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_WARNING_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn', ]); expect(mockError).toHaveBeenCalledTimes(2); expect(mockError.mock.calls[0]).toHaveLength(1); expect(mockError.mock.calls[0][0]).toBe('error'); - expect(mockError.mock.calls[1]).toHaveLength(3); + expect(mockError.mock.calls[1]).toHaveLength(2); expect(mockError.mock.calls[1]).toEqual([ - '%c%s', - `color: ${process.env.DARK_MODE_DIMMED_ERROR_COLOR}`, + '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error', ]); }); @@ -1061,11 +998,12 @@ describe('console', () => { expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual( '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', ); - expect(mockWarn.mock.calls[1]).toHaveLength(4); - expect(mockWarn.mock.calls[1][0]).toEqual('%c%s %s'); - expect(mockWarn.mock.calls[1][1]).toMatch('color: rgba('); - expect(mockWarn.mock.calls[1][2]).toEqual('warn'); - expect(normalizeCodeLocInfo(mockWarn.mock.calls[1][3]).trim()).toEqual( + expect(mockWarn.mock.calls[1]).toHaveLength(3); + expect(mockWarn.mock.calls[1][0]).toEqual( + '\x1b[2;38;2;124;124;124m%s %s\x1b[0m', + ); + expect(mockWarn.mock.calls[1][1]).toMatch('warn'); + expect(normalizeCodeLocInfo(mockWarn.mock.calls[1][2]).trim()).toEqual( 'in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', ); @@ -1074,11 +1012,12 @@ describe('console', () => { expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toEqual( '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', ); - expect(mockError.mock.calls[1]).toHaveLength(4); - expect(mockError.mock.calls[1][0]).toEqual('%c%s %s'); - expect(mockError.mock.calls[1][1]).toMatch('color: rgba('); - expect(mockError.mock.calls[1][2]).toEqual('error'); - expect(normalizeCodeLocInfo(mockError.mock.calls[1][3]).trim()).toEqual( + expect(mockError.mock.calls[1]).toHaveLength(3); + expect(mockError.mock.calls[1][0]).toEqual( + '\x1b[2;38;2;124;124;124m%s %s\x1b[0m', + ); + expect(mockError.mock.calls[1][1]).toEqual('error'); + expect(normalizeCodeLocInfo(mockError.mock.calls[1][2]).trim()).toEqual( 'in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', ); }); diff --git a/packages/react-devtools-shared/src/backend/console.js b/packages/react-devtools-shared/src/backend/console.js index 0aa0bcdbff8db..081df398893da 100644 --- a/packages/react-devtools-shared/src/backend/console.js +++ b/packages/react-devtools-shared/src/backend/console.js @@ -15,8 +15,13 @@ import type { WorkTagMap, ConsolePatchSettings, } from './types'; -import {format, formatWithStyles} from './utils'; +import {formatWithStyles} from './utils'; +import { + FIREFOX_CONSOLE_DIMMING_COLOR, + ANSI_STYLE_DIMMING_TEMPLATE, + ANSI_STYLE_DIMMING_TEMPLATE_WITH_COMPONENT_STACK, +} from 'react-devtools-shared/src/constants'; import {getInternalReactConstants, getDispatcherRef} from './renderer'; import { getStackByFiberInDevAndProd, @@ -25,7 +30,6 @@ import { import {castBool, castBrowserTheme} from '../utils'; const OVERRIDE_CONSOLE_METHODS = ['error', 'trace', 'warn']; -const DIMMED_NODE_CONSOLE_COLOR = '\x1b[2m%s\x1b[0m'; // React's custom built component stack strings match "\s{4}in" // Chrome's prefix matches "\s{4}at" @@ -44,31 +48,18 @@ const STYLE_DIRECTIVE_REGEX = /^%c/; // method has been overridden by the patchForStrictMode function. // If it has we'll need to do some special formatting of the arguments // so the console color stays consistent -function isStrictModeOverride(args: Array, method: string): boolean { - return ( - args.length >= 2 && - STYLE_DIRECTIVE_REGEX.test(args[0]) && - args[1] === `color: ${getConsoleColor(method) || ''}` - ); -} - -function getConsoleColor(method: string): ?string { - switch (method) { - case 'warn': - return consoleSettingsRef.browserTheme === 'light' - ? process.env.LIGHT_MODE_DIMMED_WARNING_COLOR - : process.env.DARK_MODE_DIMMED_WARNING_COLOR; - case 'error': - return consoleSettingsRef.browserTheme === 'light' - ? process.env.LIGHT_MODE_DIMMED_ERROR_COLOR - : process.env.DARK_MODE_DIMMED_ERROR_COLOR; - case 'log': - default: - return consoleSettingsRef.browserTheme === 'light' - ? process.env.LIGHT_MODE_DIMMED_LOG_COLOR - : process.env.DARK_MODE_DIMMED_LOG_COLOR; +function isStrictModeOverride(args: Array): boolean { + if (__IS_FIREFOX__) { + return ( + args.length >= 2 && + STYLE_DIRECTIVE_REGEX.test(args[0]) && + args[1] === FIREFOX_CONSOLE_DIMMING_COLOR + ); + } else { + return args.length >= 2 && args[0] === ANSI_STYLE_DIMMING_TEMPLATE; } } + type OnErrorOrWarning = ( fiber: Fiber, type: 'error' | 'warn', @@ -93,11 +84,6 @@ for (const method in console) { let unpatchFn: null | (() => void) = null; -let isNode = false; -try { - isNode = this === global; -} catch (error) {} - // Enables e.g. Jest tests to inject a mock console object. export function dangerous_setTargetConsoleForTesting( targetConsoleForTesting: Object, @@ -247,9 +233,15 @@ export function patch({ (currentDispatcherRef: any), ); if (componentStack !== '') { - if (isStrictModeOverride(args, method)) { - args[0] = `${args[0]} %s`; - args.push(componentStack); + if (isStrictModeOverride(args)) { + if (__IS_FIREFOX__) { + args[0] = `${args[0]} %s`; + args.push(componentStack); + } else { + args[0] = + ANSI_STYLE_DIMMING_TEMPLATE_WITH_COMPONENT_STACK; + args.push(componentStack); + } } else { args.push(componentStack); } @@ -337,17 +329,13 @@ export function patchForStrictMode() { // $FlowFixMe[missing-local-annot] const overrideMethod = (...args) => { if (!consoleSettingsRef.hideConsoleLogsInStrictMode) { - // Dim the text color of the double logs if we're not - // hiding them. - if (isNode) { - originalMethod(DIMMED_NODE_CONSOLE_COLOR, format(...args)); + // Dim the text color of the double logs if we're not hiding them. + if (__IS_FIREFOX__) { + originalMethod( + ...formatWithStyles(args, FIREFOX_CONSOLE_DIMMING_COLOR), + ); } else { - const color = getConsoleColor(method); - if (color) { - originalMethod(...formatWithStyles(args, `color: ${color}`)); - } else { - throw Error('Console color is not defined'); - } + originalMethod(ANSI_STYLE_DIMMING_TEMPLATE, ...args); } } }; diff --git a/packages/react-devtools-shared/src/constants.js b/packages/react-devtools-shared/src/constants.js index b73c178bf2980..303ae502880a8 100644 --- a/packages/react-devtools-shared/src/constants.js +++ b/packages/react-devtools-shared/src/constants.js @@ -29,46 +29,37 @@ export const PROFILING_FLAG_BASIC_SUPPORT = 0b01; export const PROFILING_FLAG_TIMELINE_SUPPORT = 0b10; export const LOCAL_STORAGE_DEFAULT_TAB_KEY = 'React::DevTools::defaultTab'; - export const LOCAL_STORAGE_COMPONENT_FILTER_PREFERENCES_KEY = 'React::DevTools::componentFilters'; - export const SESSION_STORAGE_LAST_SELECTION_KEY = 'React::DevTools::lastSelection'; - export const LOCAL_STORAGE_OPEN_IN_EDITOR_URL = 'React::DevTools::openInEditorUrl'; - export const LOCAL_STORAGE_OPEN_IN_EDITOR_URL_PRESET = 'React::DevTools::openInEditorUrlPreset'; - export const LOCAL_STORAGE_PARSE_HOOK_NAMES_KEY = 'React::DevTools::parseHookNames'; - export const SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY = 'React::DevTools::recordChangeDescriptions'; - export const SESSION_STORAGE_RELOAD_AND_PROFILE_KEY = 'React::DevTools::reloadAndProfile'; - export const LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS = 'React::DevTools::breakOnConsoleErrors'; - export const LOCAL_STORAGE_BROWSER_THEME = 'React::DevTools::theme'; - export const LOCAL_STORAGE_SHOULD_APPEND_COMPONENT_STACK_KEY = 'React::DevTools::appendComponentStack'; - export const LOCAL_STORAGE_SHOW_INLINE_WARNINGS_AND_ERRORS_KEY = 'React::DevTools::showInlineWarningsAndErrors'; - export const LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY = 'React::DevTools::traceUpdatesEnabled'; - export const LOCAL_STORAGE_HIDE_CONSOLE_LOGS_IN_STRICT_MODE = 'React::DevTools::hideConsoleLogsInStrictMode'; - export const LOCAL_STORAGE_SUPPORTS_PROFILING_KEY = 'React::DevTools::supportsProfiling'; export const PROFILER_EXPORT_VERSION = 5; + +export const FIREFOX_CONSOLE_DIMMING_COLOR = 'color: rgba(124, 124, 124, 0.75)'; +export const ANSI_STYLE_DIMMING_TEMPLATE = '\x1b[2;38;2;124;124;124m%s\x1b[0m'; +export const ANSI_STYLE_DIMMING_TEMPLATE_WITH_COMPONENT_STACK = + '\x1b[2;38;2;124;124;124m%s %s\x1b[0m'; diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index 3f40efaf218c5..d16c09e8ce77c 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -8,7 +8,6 @@ * @flow */ -import type {BrowserTheme} from './frontend/types'; import type { DevToolsHook, Handler, @@ -18,6 +17,11 @@ import type { DevToolsBackend, } from './backend/types'; +import { + FIREFOX_CONSOLE_DIMMING_COLOR, + ANSI_STYLE_DIMMING_TEMPLATE, +} from 'react-devtools-shared/src/constants'; + declare var window: any; export function installHook(target: any): DevToolsHook | null { @@ -225,13 +229,9 @@ export function installHook(target: any): DevToolsHook | null { // React and DevTools are connecting and the renderer interface isn't avaiable // and we want to be able to have consistent logging behavior for double logs // during the initial renderer. - function patchConsoleForInitialCommitInStrictMode({ - hideConsoleLogsInStrictMode, - browserTheme, - }: { + function patchConsoleForInitialCommitInStrictMode( hideConsoleLogsInStrictMode: boolean, - browserTheme: BrowserTheme, - }) { + ) { const overrideConsoleMethods = [ 'error', 'group', @@ -266,36 +266,15 @@ export function installHook(target: any): DevToolsHook | null { : targetConsole[method]); const overrideMethod = (...args: $ReadOnlyArray) => { + // Dim the text color of the double logs if we're not hiding them. if (!hideConsoleLogsInStrictMode) { - // Dim the text color of the double logs if we're not - // hiding them. - let color; - switch (method) { - case 'warn': - color = - browserTheme === 'light' - ? process.env.LIGHT_MODE_DIMMED_WARNING_COLOR - : process.env.DARK_MODE_DIMMED_WARNING_COLOR; - break; - case 'error': - color = - browserTheme === 'light' - ? process.env.LIGHT_MODE_DIMMED_ERROR_COLOR - : process.env.DARK_MODE_DIMMED_ERROR_COLOR; - break; - case 'log': - default: - color = - browserTheme === 'light' - ? process.env.LIGHT_MODE_DIMMED_LOG_COLOR - : process.env.DARK_MODE_DIMMED_LOG_COLOR; - break; - } - - if (color) { - originalMethod(...formatWithStyles(args, `color: ${color}`)); + // Firefox doesn't support ANSI escape sequences + if (__IS_FIREFOX__) { + originalMethod( + ...formatWithStyles(args, FIREFOX_CONSOLE_DIMMING_COLOR), + ); } else { - throw Error('Console color is not defined'); + originalMethod(ANSI_STYLE_DIMMING_TEMPLATE, ...args); } } }; @@ -456,12 +435,8 @@ export function installHook(target: any): DevToolsHook | null { if (isStrictMode) { const hideConsoleLogsInStrictMode = window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ === true; - const browserTheme = window.__REACT_DEVTOOLS_BROWSER_THEME__; - patchConsoleForInitialCommitInStrictMode({ - hideConsoleLogsInStrictMode, - browserTheme, - }); + patchConsoleForInitialCommitInStrictMode(hideConsoleLogsInStrictMode); } else { unpatchConsoleForInitialCommitInStrictMode(); } diff --git a/packages/react-devtools-shell/webpack-server.js b/packages/react-devtools-shell/webpack-server.js index 2c78520a6d4eb..467bd6cfa363b 100644 --- a/packages/react-devtools-shell/webpack-server.js +++ b/packages/react-devtools-shell/webpack-server.js @@ -2,12 +2,6 @@ const {resolve} = require('path'); const Webpack = require('webpack'); const WebpackDevServer = require('webpack-dev-server'); const { - DARK_MODE_DIMMED_WARNING_COLOR, - DARK_MODE_DIMMED_ERROR_COLOR, - DARK_MODE_DIMMED_LOG_COLOR, - LIGHT_MODE_DIMMED_WARNING_COLOR, - LIGHT_MODE_DIMMED_ERROR_COLOR, - LIGHT_MODE_DIMMED_LOG_COLOR, GITHUB_URL, getVersionString, } = require('react-devtools-extensions/utils'); @@ -81,12 +75,6 @@ const makeConfig = (entry, alias) => ({ 'process.env.EDITOR_URL': EDITOR_URL != null ? `"${EDITOR_URL}"` : null, 'process.env.DEVTOOLS_PACKAGE': `"react-devtools-shell"`, 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, - 'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_ERROR_COLOR': `"${DARK_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.DARK_MODE_DIMMED_LOG_COLOR': `"${DARK_MODE_DIMMED_LOG_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_WARNING_COLOR': `"${LIGHT_MODE_DIMMED_WARNING_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_ERROR_COLOR': `"${LIGHT_MODE_DIMMED_ERROR_COLOR}"`, - 'process.env.LIGHT_MODE_DIMMED_LOG_COLOR': `"${LIGHT_MODE_DIMMED_LOG_COLOR}"`, 'process.env.E2E_APP_REACT_VERSION': `"${REACT_VERSION}"`, }), ], diff --git a/scripts/flow/react-devtools.js b/scripts/flow/react-devtools.js index 361ca168190ef..67355481e9fd4 100644 --- a/scripts/flow/react-devtools.js +++ b/scripts/flow/react-devtools.js @@ -12,9 +12,4 @@ declare const __EXTENSION__: boolean; declare const __TEST__: boolean; -declare const DARK_MODE_DIMMED_WARNING_COLOR: string; -declare const DARK_MODE_DIMMED_ERROR_COLOR: string; -declare const DARK_MODE_DIMMED_LOG_COLOR: string; -declare const LIGHT_MODE_DIMMED_WARNING_COLOR: string; -declare const LIGHT_MODE_DIMMED_ERROR_COLOR: string; -declare const LIGHT_MODE_DIMMED_LOG_COLOR: string; +declare const __IS_FIREFOX__: boolean; diff --git a/scripts/jest/devtools/setupEnv.js b/scripts/jest/devtools/setupEnv.js index eadbbcb0afaed..fd9be56c5c7f8 100644 --- a/scripts/jest/devtools/setupEnv.js +++ b/scripts/jest/devtools/setupEnv.js @@ -3,15 +3,6 @@ const semver = require('semver'); const {ReactVersion} = require('../../../ReactVersions'); -const { - DARK_MODE_DIMMED_WARNING_COLOR, - DARK_MODE_DIMMED_ERROR_COLOR, - DARK_MODE_DIMMED_LOG_COLOR, - LIGHT_MODE_DIMMED_WARNING_COLOR, - LIGHT_MODE_DIMMED_ERROR_COLOR, - LIGHT_MODE_DIMMED_LOG_COLOR, -} = require('react-devtools-extensions/utils'); - // DevTools stores preferences between sessions in localStorage if (!global.hasOwnProperty('localStorage')) { global.localStorage = require('local-storage-fallback').default; @@ -20,16 +11,7 @@ if (!global.hasOwnProperty('localStorage')) { // Mimic the global we set with Webpack's DefinePlugin global.__DEV__ = process.env.NODE_ENV !== 'production'; global.__TEST__ = true; - -global.process.env.DARK_MODE_DIMMED_WARNING_COLOR = - DARK_MODE_DIMMED_WARNING_COLOR; -global.process.env.DARK_MODE_DIMMED_ERROR_COLOR = DARK_MODE_DIMMED_ERROR_COLOR; -global.process.env.DARK_MODE_DIMMED_LOG_COLOR = DARK_MODE_DIMMED_LOG_COLOR; -global.process.env.LIGHT_MODE_DIMMED_WARNING_COLOR = - LIGHT_MODE_DIMMED_WARNING_COLOR; -global.process.env.LIGHT_MODE_DIMMED_ERROR_COLOR = - LIGHT_MODE_DIMMED_ERROR_COLOR; -global.process.env.LIGHT_MODE_DIMMED_LOG_COLOR = LIGHT_MODE_DIMMED_LOG_COLOR; +global.__IS_FIREFOX__ = false; const ReactVersionTestingAgainst = process.env.REACT_VERSION || ReactVersion; From 91096cf95fa22b4195d9b6f18aabb8dd2e058939 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 12 Jun 2024 17:24:14 +0100 Subject: [PATCH 3/4] chore[react-devtools]: improve console arguments formatting before passing it to original console --- .../src/__tests__/utils-test.js | 90 ++++++++++++++----- .../src/backend/console.js | 10 ++- .../src/backend/renderer.js | 11 ++- .../src/backend/utils.js | 66 +++++++++++++- packages/react-devtools-shared/src/hook.js | 60 ++++++++++++- 5 files changed, 209 insertions(+), 28 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/utils-test.js b/packages/react-devtools-shared/src/__tests__/utils-test.js index 71cd2aaf38dc0..9e781e072ba75 100644 --- a/packages/react-devtools-shared/src/__tests__/utils-test.js +++ b/packages/react-devtools-shared/src/__tests__/utils-test.js @@ -14,7 +14,8 @@ import { } from 'react-devtools-shared/src/utils'; import {stackToComponentSources} from 'react-devtools-shared/src/devtools/utils'; import { - format, + formatConsoleArguments, + formatConsoleArgumentsToSingleString, formatWithStyles, gt, gte, @@ -123,51 +124,51 @@ describe('utils', () => { }); }); - describe('format', () => { - // @reactVersion >= 16.0 + describe('formatConsoleArgumentsToSingleString', () => { it('should format simple strings', () => { - expect(format('a', 'b', 'c')).toEqual('a b c'); + expect(formatConsoleArgumentsToSingleString('a', 'b', 'c')).toEqual( + 'a b c', + ); }); - // @reactVersion >= 16.0 it('should format multiple argument types', () => { - expect(format('abc', 123, true)).toEqual('abc 123 true'); + expect(formatConsoleArgumentsToSingleString('abc', 123, true)).toEqual( + 'abc 123 true', + ); }); - // @reactVersion >= 16.0 it('should support string substitutions', () => { - expect(format('a %s b %s c', 123, true)).toEqual('a 123 b true c'); + expect( + formatConsoleArgumentsToSingleString('a %s b %s c', 123, true), + ).toEqual('a 123 b true c'); }); - // @reactVersion >= 16.0 it('should gracefully handle Symbol types', () => { - expect(format(Symbol('a'), 'b', Symbol('c'))).toEqual( - 'Symbol(a) b Symbol(c)', - ); + expect( + formatConsoleArgumentsToSingleString(Symbol('a'), 'b', Symbol('c')), + ).toEqual('Symbol(a) b Symbol(c)'); }); - // @reactVersion >= 16.0 it('should gracefully handle Symbol type for the first argument', () => { - expect(format(Symbol('abc'), 123)).toEqual('Symbol(abc) 123'); + expect(formatConsoleArgumentsToSingleString(Symbol('abc'), 123)).toEqual( + 'Symbol(abc) 123', + ); }); }); describe('formatWithStyles', () => { - // @reactVersion >= 16.0 it('should format empty arrays', () => { expect(formatWithStyles([])).toEqual([]); expect(formatWithStyles([], 'gray')).toEqual([]); expect(formatWithStyles(undefined)).toEqual(undefined); }); - // @reactVersion >= 16.0 it('should bail out of strings with styles', () => { expect( formatWithStyles(['%ca', 'color: green', 'b', 'c'], 'color: gray'), ).toEqual(['%ca', 'color: green', 'b', 'c']); }); - // @reactVersion >= 16.0 it('should format simple strings', () => { expect(formatWithStyles(['a'])).toEqual(['a']); @@ -186,7 +187,6 @@ describe('utils', () => { ]); }); - // @reactVersion >= 16.0 it('should format string substituions', () => { expect( formatWithStyles(['%s %s %s', 'a', 'b', 'c'], 'color: gray'), @@ -199,7 +199,6 @@ describe('utils', () => { ); }); - // @reactVersion >= 16.0 it('should support multiple argument types', () => { const symbol = Symbol('a'); expect( @@ -219,7 +218,6 @@ describe('utils', () => { ]); }); - // @reactVersion >= 16.0 it('should properly format escaped string substituions', () => { expect(formatWithStyles(['%%s'], 'color: gray')).toEqual([ '%c%s', @@ -234,7 +232,6 @@ describe('utils', () => { expect(formatWithStyles(['%%c%c'], 'color: gray')).toEqual(['%%c%c']); }); - // @reactVersion >= 16.0 it('should format non string inputs as the first argument', () => { expect(formatWithStyles([{foo: 'bar'}])).toEqual([{foo: 'bar'}]); expect(formatWithStyles([[1, 2, 3]])).toEqual([[1, 2, 3]]); @@ -387,4 +384,55 @@ describe('utils', () => { }); }); }); + + describe('formatConsoleArguments', () => { + it('works with empty arguments list', () => { + expect(formatConsoleArguments(...[])).toEqual([]); + }); + + it('works for string without escape sequences', () => { + expect( + formatConsoleArguments('This is the template', 'And another string'), + ).toEqual(['This is the template', 'And another string']); + }); + + it('works with strings templates', () => { + expect(formatConsoleArguments('This is %s template', 'the')).toEqual([ + 'This is the template', + ]); + }); + + it('skips %%s', () => { + expect(formatConsoleArguments('This %%s is %s template', 'the')).toEqual([ + 'This %%s is the template', + ]); + }); + + it('works with %%%s', () => { + expect( + formatConsoleArguments('This %%%s is %s template', 'test', 'the'), + ).toEqual(['This %%test is the template']); + }); + + it("doesn't inline objects", () => { + expect( + formatConsoleArguments('This is %s template with object %o', 'the', {}), + ).toEqual(['This is the template with object %o', {}]); + }); + + it("doesn't inline css", () => { + expect( + formatConsoleArguments( + 'This is template with %c %s object %o', + 'color: rgba(...)', + 'the', + {}, + ), + ).toEqual([ + 'This is template with %c the object %o', + 'color: rgba(...)', + {}, + ]); + }); + }); }); diff --git a/packages/react-devtools-shared/src/backend/console.js b/packages/react-devtools-shared/src/backend/console.js index 081df398893da..524bad82cca2b 100644 --- a/packages/react-devtools-shared/src/backend/console.js +++ b/packages/react-devtools-shared/src/backend/console.js @@ -15,8 +15,11 @@ import type { WorkTagMap, ConsolePatchSettings, } from './types'; -import {formatWithStyles} from './utils'; +import { + formatConsoleArguments, + formatWithStyles, +} from 'react-devtools-shared/src/backend/utils'; import { FIREFOX_CONSOLE_DIMMING_COLOR, ANSI_STYLE_DIMMING_TEMPLATE, @@ -335,7 +338,10 @@ export function patchForStrictMode() { ...formatWithStyles(args, FIREFOX_CONSOLE_DIMMING_COLOR), ); } else { - originalMethod(ANSI_STYLE_DIMMING_TEMPLATE, ...args); + originalMethod( + ANSI_STYLE_DIMMING_TEMPLATE, + ...formatConsoleArguments(...args), + ); } } }; diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index 2e6cc9b287812..b75e56c111848 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -40,6 +40,7 @@ import { } from 'react-devtools-shared/src/utils'; import {sessionStorageGetItem} from 'react-devtools-shared/src/storage'; import { + formatConsoleArgumentsToSingleString, gt, gte, parseSourceFromComponentStack, @@ -95,7 +96,6 @@ import { MEMO_SYMBOL_STRING, SERVER_CONTEXT_SYMBOL_STRING, } from './ReactSymbols'; -import {format} from './utils'; import {enableStyleXFeatures} from 'react-devtools-feature-flags'; import is from 'shared/objectIs'; import hasOwnProperty from 'shared/hasOwnProperty'; @@ -841,7 +841,14 @@ export function attach( return; } } - const message = format(...args); + + // We can't really use this message as a unique key, since we can't distinguish + // different objects in this implementation. We have to delegate displaying of the objects + // to the environment, the browser console, for example, so this is why this should be kept + // as an array of arguments, instead of the plain string. + // [Warning: %o, {...}] and [Warning: %o, {...}] will be considered as the same message, + // even if objects are different + const message = formatConsoleArgumentsToSingleString(...args); if (__DEBUG__) { debug('onErrorOrWarning', fiber, null, `${type}: "${message}"`); } diff --git a/packages/react-devtools-shared/src/backend/utils.js b/packages/react-devtools-shared/src/backend/utils.js index ace070d8b6dd8..bd762467b6481 100644 --- a/packages/react-devtools-shared/src/backend/utils.js +++ b/packages/react-devtools-shared/src/backend/utils.js @@ -164,6 +164,7 @@ export function serializeToString(data: any): string { ); } +// NOTE: KEEP IN SYNC with src/hook.js // Formats an array of args with a style for console methods, using // the following algorithm: // 1. The first param is a string that contains %c @@ -220,11 +221,72 @@ export function formatWithStyles( } } +// NOTE: KEEP IN SYNC with src/hook.js +// Skips CSS and object arguments, inlines other in the first argument as a template string +export function formatConsoleArguments( + maybeMessage: any, + ...inputArgs: $ReadOnlyArray +): $ReadOnlyArray { + if (inputArgs.length === 0 || typeof maybeMessage !== 'string') { + return [maybeMessage, ...inputArgs]; + } + + const args = inputArgs.slice(); + + let template = ''; + let argumentsPointer = 0; + for (let i = 0; i < maybeMessage.length; ++i) { + const currentChar = maybeMessage[i]; + if (currentChar !== '%') { + template += currentChar; + continue; + } + + const nextChar = maybeMessage[i + 1]; + ++i; + + // Only keep CSS and objects, inline other arguments + switch (nextChar) { + case 'c': + case 'O': + case 'o': { + ++argumentsPointer; + template += `%${nextChar}`; + + break; + } + case 'd': + case 'i': { + const [arg] = args.splice(argumentsPointer, 1); + template += parseInt(arg, 10).toString(); + + break; + } + case 'f': { + const [arg] = args.splice(argumentsPointer, 1); + template += parseFloat(arg).toString(); + + break; + } + case 's': { + const [arg] = args.splice(argumentsPointer, 1); + template += arg.toString(); + + break; + } + + default: + template += `%${nextChar}`; + } + } + + return [template, ...args]; +} + // based on https://github.com/tmpfs/format-util/blob/0e62d430efb0a1c51448709abd3e2406c14d8401/format.js#L1 // based on https://developer.mozilla.org/en-US/docs/Web/API/console#Using_string_substitutions // Implements s, d, i and f placeholders -// NOTE: KEEP IN SYNC with src/hook.js -export function format( +export function formatConsoleArgumentsToSingleString( maybeMessage: any, ...inputArgs: $ReadOnlyArray ): string { diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index d16c09e8ce77c..0dd96dc471cbc 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -220,6 +220,61 @@ export function installHook(target: any): DevToolsHook | null { return [firstArg, style, ...inputArgs]; } } + // NOTE: KEEP IN SYNC with src/backend/utils.js + function formatConsoleArguments( + maybeMessage: any, + ...inputArgs: $ReadOnlyArray + ): $ReadOnlyArray { + if (inputArgs.length === 0 || typeof maybeMessage !== 'string') { + return [maybeMessage, ...inputArgs]; + } + + const args = inputArgs.slice(); + + let template = ''; + let argumentsPointer = 0; + for (let i = 0; i < maybeMessage.length; ++i) { + const currentChar = maybeMessage[i]; + if (currentChar !== '%') { + template += currentChar; + continue; + } + + const nextChar = maybeMessage[i + 1]; + ++i; + + // Only keep CSS and objects, inline other arguments + switch (nextChar) { + case 'c': + case 'O': + case 'o': { + ++argumentsPointer; + template += `%${nextChar}`; + + break; + } + case 'd': + case 'i': { + const [arg] = args.splice(argumentsPointer, 1); + template += parseInt(arg, 10).toString(); + + break; + } + case 'f': { + const [arg] = args.splice(argumentsPointer, 1); + template += parseFloat(arg).toString(); + + break; + } + case 's': { + const [arg] = args.splice(argumentsPointer, 1); + template += arg.toString(); + } + } + } + + return [template, ...args]; + } let unpatchFn = null; @@ -274,7 +329,10 @@ export function installHook(target: any): DevToolsHook | null { ...formatWithStyles(args, FIREFOX_CONSOLE_DIMMING_COLOR), ); } else { - originalMethod(ANSI_STYLE_DIMMING_TEMPLATE, ...args); + originalMethod( + ANSI_STYLE_DIMMING_TEMPLATE, + ...formatConsoleArguments(...args), + ); } } }; From 7fba323a6f9e6245ea54d9f97cb888463564a637 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 13 Jun 2024 15:39:35 +0100 Subject: [PATCH 4/4] toggle consoleManagedByDevToolsDuringStrictMode flag for native --- packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js | 1 - packages/shared/forks/ReactFeatureFlags.native-fb.js | 2 +- packages/shared/forks/ReactFeatureFlags.native-oss.js | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js index ecdb3755691d2..227f923e94648 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -18,7 +18,6 @@ // add a test configuration for React Native. export const alwaysThrottleRetries = __VARIANT__; -export const consoleManagedByDevToolsDuringStrictMode = __VARIANT__; export const disableDefaultPropsExceptForClasses = __VARIANT__; export const enableAddPropertiesFastPath = __VARIANT__; export const enableDeferRootSchedulingToMicrotask = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index c306b2a6a28ed..c6574371cee76 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -20,7 +20,6 @@ const dynamicFlags: DynamicExportsType = (dynamicFlagsUntyped: any); // the exports object every time a flag is read. export const { alwaysThrottleRetries, - consoleManagedByDevToolsDuringStrictMode, disableDefaultPropsExceptForClasses, enableAddPropertiesFastPath, enableDeferRootSchedulingToMicrotask, @@ -70,6 +69,7 @@ export const enableLegacyFBSupport = false; export const enableFilterEmptyStringAttributesDOM = true; export const enableGetInspectorDataForInstanceInProduction = true; export const useModernStrictMode = true; +export const consoleManagedByDevToolsDuringStrictMode = true; export const renameElementSymbol = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 63fe1885c0bda..58c447001033d 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -25,7 +25,6 @@ export const disableLegacyMode = __TODO_NEXT_RN_MAJOR__; export const useModernStrictMode = __TODO_NEXT_RN_MAJOR__; export const enableReactTestRendererWarning = __TODO_NEXT_RN_MAJOR__; export const enableAsyncActions = __TODO_NEXT_RN_MAJOR__; -export const consoleManagedByDevToolsDuringStrictMode = __TODO_NEXT_RN_MAJOR__; export const enableDeferRootSchedulingToMicrotask = __TODO_NEXT_RN_MAJOR__; export const alwaysThrottleRetries = __TODO_NEXT_RN_MAJOR__; export const enableInfiniteRenderLoopDetection = __TODO_NEXT_RN_MAJOR__; @@ -54,6 +53,7 @@ export const enableFizzExternalRuntime = __NEXT_RN_MAJOR__; // DOM-only export const enableBinaryFlight = true; export const enableFlightReadableStream = true; export const enableServerComponentLogs = __NEXT_RN_MAJOR__; +export const consoleManagedByDevToolsDuringStrictMode = __NEXT_RN_MAJOR__; // DEV-only but enabled in the next RN Major. // Not supported by flag script to avoid the special case.