Skip to content

Commit bcf97c7

Browse files
emily8rownhoxyq
andauthored
Devtools disable log dimming strict mode setting (#35207)
<!-- 1. Fork [the repository](https://github.com/facebook/react) and create your branch from `main`. 2. Run `yarn` in the repository root. 3. If you've fixed a bug or added code that should be tested, add tests! 4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch TestName` is helpful in development. 5. Run `yarn test --prod` to test in the production environment. It supports the same options as `yarn test`. 6. If you need a debugger, run `yarn test --debug --watch TestName`, open `chrome://inspect`, and press "Inspect". 7. Format your code with [prettier](https://github.com/prettier/prettier) (`yarn prettier`). 8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only check changed files. 9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`). --> ## Summary Currently, every second console log is dimmed, receiving a special style that indicates to user that it was raising because of [React Strict Mode](https://react.dev/reference/react/StrictMode) second rendering. This introduces a setting to disable this. ## How did you test this change? Test in console-test.js https://github.com/user-attachments/assets/af6663ac-f79b-4824-95c0-d46b0c8dec12 Browser extension react devtools https://github.com/user-attachments/assets/7e2ecb7a-fbdf-4c72-ab45-7e3a1c6e5e44 React native dev tools: https://github.com/user-attachments/assets/d875b3ac-1f27-43f8-8d9d-12b2d65fa6e6 --------- Co-authored-by: Ruslan Lesiutin <28902667+hoxyq@users.noreply.github.com>
1 parent ba5b843 commit bcf97c7

File tree

9 files changed

+165
-15
lines changed

9 files changed

+165
-15
lines changed

packages/react-devtools-core/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ if (process.env.NODE_ENV !== 'production') {
3232
#### `Settings`
3333
| Spec | Default value |
3434
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
35-
| <pre>{<br> appendComponentStack: boolean,<br> breakOnConsoleErrors: boolean,<br> showInlineWarningsAndErrors: boolean,<br> hideConsoleLogsInStrictMode: boolean<br>}</pre> | <pre>{<br> appendComponentStack: true,<br> breakOnConsoleErrors: false,<br> showInlineWarningsAndErrors: true,<br> hideConsoleLogsInStrictMode: false<br>}</pre> |
35+
| <pre>{<br> appendComponentStack: boolean,<br> breakOnConsoleErrors: boolean,<br> showInlineWarningsAndErrors: boolean,<br> hideConsoleLogsInStrictMode: boolean,<br> disableSecondConsoleLogDimmingInStrictMode: boolean<br>}</pre> | <pre>{<br> appendComponentStack: true,<br> breakOnConsoleErrors: false,<br> showInlineWarningsAndErrors: true,<br> hideConsoleLogsInStrictMode: false,<br> disableSecondConsoleLogDimmingInStrictMode: false<br>}</pre> |
3636

3737
### `connectToDevTools` options
3838
| Prop | Default | Description |
@@ -53,7 +53,7 @@ if (process.env.NODE_ENV !== 'production') {
5353
| `onSubscribe` | Function, which receives listener (function, with a single argument) as an argument. Called when backend subscribes to messages from the other end (frontend). |
5454
| `onUnsubscribe` | Function, which receives listener (function) as an argument. Called when backend unsubscribes to messages from the other end (frontend). |
5555
| `onMessage` | Function, which receives 2 arguments: event (string) and payload (any). Called when backend emits a message, which should be sent to the frontend. |
56-
| `onSettingsUpdated` | A callback that will be called when the user updates the settings in the UI. You can use it for persisting user settings. |
56+
| `onSettingsUpdated` | A callback that will be called when the user updates the settings in the UI. You can use it for persisting user settings. |
5757

5858
Unlike `connectToDevTools`, `connectWithCustomMessagingProtocol` returns a callback, which can be used for unsubscribing the backend from the global DevTools hook.
5959

packages/react-devtools-extensions/src/contentScripts/hookSettingsInjector.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ async function messageListener(event: MessageEvent) {
2424
if (typeof settings.hideConsoleLogsInStrictMode !== 'boolean') {
2525
settings.hideConsoleLogsInStrictMode = false;
2626
}
27+
if (
28+
typeof settings.disableSecondConsoleLogDimmingInStrictMode !== 'boolean'
29+
) {
30+
settings.disableSecondConsoleLogDimmingInStrictMode = false;
31+
}
2732

2833
window.postMessage({
2934
source: 'react-devtools-hook-settings-injector',

packages/react-devtools-inline/src/backend.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ function startActivation(contentWindow: any, bridge: BackendBridge) {
2727
componentFilters,
2828
showInlineWarningsAndErrors,
2929
hideConsoleLogsInStrictMode,
30+
disableSecondConsoleLogDimmingInStrictMode,
3031
} = data;
3132

3233
contentWindow.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ =
@@ -38,6 +39,8 @@ function startActivation(contentWindow: any, bridge: BackendBridge) {
3839
showInlineWarningsAndErrors;
3940
contentWindow.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ =
4041
hideConsoleLogsInStrictMode;
42+
contentWindow.__REACT_DEVTOOLS_DISABLE_SECOND_CONSOLE_LOG_DIMMING_IN_STRICT_MODE__ =
43+
disableSecondConsoleLogDimmingInStrictMode;
4144

4245
// TRICKY
4346
// The backend entry point may be required in the context of an iframe or the parent window.
@@ -53,6 +56,8 @@ function startActivation(contentWindow: any, bridge: BackendBridge) {
5356
showInlineWarningsAndErrors;
5457
window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ =
5558
hideConsoleLogsInStrictMode;
59+
window.__REACT_DEVTOOLS_DISABLE_SECOND_CONSOLE_LOG_DIMMING_IN_STRICT_MODE__ =
60+
disableSecondConsoleLogDimmingInStrictMode;
5661
}
5762

5863
finishActivation(contentWindow, bridge);

packages/react-devtools-shared/src/__tests__/console-test.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,4 +733,85 @@ describe('console', () => {
733733
: 'in Child (at **)\n in Intermediate (at **)\n in Parent (at **)',
734734
]);
735735
});
736+
737+
it('should not dim console logs if disableSecondConsoleLogDimmingInStrictMode is enabled', () => {
738+
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false;
739+
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode =
740+
false;
741+
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.disableSecondConsoleLogDimmingInStrictMode =
742+
true;
743+
744+
const container = document.createElement('div');
745+
const root = ReactDOMClient.createRoot(container);
746+
747+
function App() {
748+
console.log('log');
749+
console.warn('warn');
750+
console.error('error');
751+
return <div />;
752+
}
753+
754+
act(() =>
755+
root.render(
756+
<React.StrictMode>
757+
<App />
758+
</React.StrictMode>,
759+
),
760+
);
761+
762+
// Both logs should be called (double logging)
763+
expect(global.consoleLogMock).toHaveBeenCalledTimes(2);
764+
expect(global.consoleWarnMock).toHaveBeenCalledTimes(2);
765+
expect(global.consoleErrorMock).toHaveBeenCalledTimes(2);
766+
767+
// The second log should NOT have dimming (no ANSI codes)
768+
expect(global.consoleLogMock.mock.calls[1]).toEqual(['log']);
769+
expect(global.consoleWarnMock.mock.calls[1]).toEqual(['warn']);
770+
expect(global.consoleErrorMock.mock.calls[1]).toEqual(['error']);
771+
});
772+
773+
it('should dim console logs if disableSecondConsoleLogDimmingInStrictMode is disabled', () => {
774+
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false;
775+
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode =
776+
false;
777+
global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.disableSecondConsoleLogDimmingInStrictMode =
778+
false;
779+
780+
const container = document.createElement('div');
781+
const root = ReactDOMClient.createRoot(container);
782+
783+
function App() {
784+
console.log('log');
785+
console.warn('warn');
786+
console.error('error');
787+
return <div />;
788+
}
789+
790+
act(() =>
791+
root.render(
792+
<React.StrictMode>
793+
<App />
794+
</React.StrictMode>,
795+
),
796+
);
797+
798+
// Both logs should be called (double logging)
799+
expect(global.consoleLogMock).toHaveBeenCalledTimes(2);
800+
expect(global.consoleWarnMock).toHaveBeenCalledTimes(2);
801+
expect(global.consoleErrorMock).toHaveBeenCalledTimes(2);
802+
803+
// The second log should have dimming (ANSI codes present)
804+
expect(global.consoleLogMock.mock.calls[1]).toEqual([
805+
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
806+
'log',
807+
]);
808+
expect(global.consoleWarnMock.mock.calls[1]).toEqual([
809+
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
810+
'warn',
811+
]);
812+
expect(global.consoleErrorMock.mock.calls[1]).toEqual([
813+
'\x1b[2;38;2;124;124;124m%s\x1b[0m',
814+
'error',
815+
]);
816+
});
736817
});

packages/react-devtools-shared/src/__tests__/setupTests.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ beforeEach(() => {
248248
breakOnConsoleErrors: false,
249249
showInlineWarningsAndErrors: true,
250250
hideConsoleLogsInStrictMode: false,
251+
disableSecondConsoleLogDimmingInStrictMode: false,
251252
});
252253

253254
const bridgeListeners = [];

packages/react-devtools-shared/src/backend/types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,4 +597,5 @@ export type DevToolsHookSettings = {
597597
breakOnConsoleErrors: boolean,
598598
showInlineWarningsAndErrors: boolean,
599599
hideConsoleLogsInStrictMode: boolean,
600+
disableSecondConsoleLogDimmingInStrictMode: boolean,
600601
};

packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ export default function DebuggingSettings({
3636
useState(usedHookSettings.hideConsoleLogsInStrictMode);
3737
const [showInlineWarningsAndErrors, setShowInlineWarningsAndErrors] =
3838
useState(usedHookSettings.showInlineWarningsAndErrors);
39+
const [
40+
disableSecondConsoleLogDimmingInStrictMode,
41+
setDisableSecondConsoleLogDimmingInStrictMode,
42+
] = useState(usedHookSettings.disableSecondConsoleLogDimmingInStrictMode);
3943

4044
useEffect(() => {
4145
store.setShouldShowWarningsAndErrors(showInlineWarningsAndErrors);
@@ -47,13 +51,15 @@ export default function DebuggingSettings({
4751
breakOnConsoleErrors,
4852
showInlineWarningsAndErrors,
4953
hideConsoleLogsInStrictMode,
54+
disableSecondConsoleLogDimmingInStrictMode,
5055
});
5156
}, [
5257
store,
5358
appendComponentStack,
5459
breakOnConsoleErrors,
5560
showInlineWarningsAndErrors,
5661
hideConsoleLogsInStrictMode,
62+
disableSecondConsoleLogDimmingInStrictMode,
5763
]);
5864

5965
return (
@@ -105,12 +111,49 @@ export default function DebuggingSettings({
105111
<input
106112
type="checkbox"
107113
checked={hideConsoleLogsInStrictMode}
114+
onChange={({currentTarget}) => {
115+
setHideConsoleLogsInStrictMode(currentTarget.checked);
116+
if (currentTarget.checked) {
117+
setDisableSecondConsoleLogDimmingInStrictMode(false);
118+
}
119+
}}
120+
className={styles.SettingRowCheckbox}
121+
/>
122+
Hide logs during additional invocations in&nbsp;
123+
<a
124+
className={styles.StrictModeLink}
125+
target="_blank"
126+
rel="noopener noreferrer"
127+
href="https://react.dev/reference/react/StrictMode">
128+
Strict Mode
129+
</a>
130+
</label>
131+
</div>
132+
133+
<div
134+
className={
135+
hideConsoleLogsInStrictMode
136+
? `${styles.SettingDisabled} ${styles.SettingWrapper}`
137+
: styles.SettingWrapper
138+
}>
139+
<label
140+
className={
141+
hideConsoleLogsInStrictMode
142+
? `${styles.SettingDisabled} ${styles.SettingRow}`
143+
: styles.SettingRow
144+
}>
145+
<input
146+
type="checkbox"
147+
checked={disableSecondConsoleLogDimmingInStrictMode}
148+
disabled={hideConsoleLogsInStrictMode}
108149
onChange={({currentTarget}) =>
109-
setHideConsoleLogsInStrictMode(currentTarget.checked)
150+
setDisableSecondConsoleLogDimmingInStrictMode(
151+
currentTarget.checked,
152+
)
110153
}
111154
className={styles.SettingRowCheckbox}
112155
/>
113-
Hide logs during additional invocations in&nbsp;
156+
Disable log dimming during additional invocations in&nbsp;
114157
<a
115158
className={styles.StrictModeLink}
116159
target="_blank"

packages/react-devtools-shared/src/devtools/views/Settings/SettingsShared.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
margin: 0.125rem 0.25rem 0.125rem 0;
2727
}
2828

29+
.SettingDisabled {
30+
opacity: 0.5;
31+
cursor: not-allowed;
32+
}
33+
2934
.OptionGroup {
3035
display: inline-flex;
3136
flex-direction: row;

packages/react-devtools-shared/src/hook.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -367,17 +367,22 @@ export function installHook(
367367
return;
368368
}
369369

370-
// Dim the text color of the double logs if we're not hiding them.
371-
// Firefox doesn't support ANSI escape sequences
372-
if (__IS_FIREFOX__) {
373-
originalMethod(
374-
...formatWithStyles(args, FIREFOX_CONSOLE_DIMMING_COLOR),
375-
);
370+
if (settings.disableSecondConsoleLogDimmingInStrictMode) {
371+
// Don't dim the console logs
372+
originalMethod(...args);
376373
} else {
377-
originalMethod(
378-
ANSI_STYLE_DIMMING_TEMPLATE,
379-
...formatConsoleArguments(...args),
380-
);
374+
// Dim the text color of the double logs if we're not hiding them.
375+
// Firefox doesn't support ANSI escape sequences
376+
if (__IS_FIREFOX__) {
377+
originalMethod(
378+
...formatWithStyles(args, FIREFOX_CONSOLE_DIMMING_COLOR),
379+
);
380+
} else {
381+
originalMethod(
382+
ANSI_STYLE_DIMMING_TEMPLATE,
383+
...formatConsoleArguments(...args),
384+
);
385+
}
381386
}
382387
};
383388

@@ -579,7 +584,10 @@ export function installHook(
579584
debugger;
580585
}
581586

582-
if (isRunningDuringStrictModeInvocation) {
587+
if (
588+
isRunningDuringStrictModeInvocation &&
589+
!settings.disableSecondConsoleLogDimmingInStrictMode
590+
) {
583591
// Dim the text color of the double logs if we're not hiding them.
584592
// Firefox doesn't support ANSI escape sequences
585593
if (__IS_FIREFOX__) {
@@ -667,6 +675,7 @@ export function installHook(
667675
breakOnConsoleErrors: false,
668676
showInlineWarningsAndErrors: true,
669677
hideConsoleLogsInStrictMode: false,
678+
disableSecondConsoleLogDimmingInStrictMode: false,
670679
};
671680
patchConsoleForErrorsAndWarnings();
672681
} else {

0 commit comments

Comments
 (0)