Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to DevTools to enable double-logging #19710

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/react-devtools-core/src/standalone.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Bridge from 'react-devtools-shared/src/bridge';
import Store from 'react-devtools-shared/src/devtools/store';
import {
getAppendComponentStack,
getsuppressDoubleLogging,
getBreakOnConsoleErrors,
getSavedComponentFilters,
} from 'react-devtools-shared/src/utils';
Expand Down Expand Up @@ -298,6 +299,9 @@ function startServer(
window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = ${JSON.stringify(
getAppendComponentStack(),
)};
window.__REACT_DEVTOOLS_SUPPRESS_DOUBLE_LOGGING__ = ${JSON.stringify(
getsuppressDoubleLogging(),
)};
window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ = ${JSON.stringify(
getBreakOnConsoleErrors(),
)};
Expand Down
5 changes: 5 additions & 0 deletions packages/react-devtools-extensions/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Store from 'react-devtools-shared/src/devtools/store';
import {getBrowserName, getBrowserTheme} from './utils';
import {LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY} from 'react-devtools-shared/src/constants';
import {
getsuppressDoubleLogging,
getAppendComponentStack,
getBreakOnConsoleErrors,
getSavedComponentFilters,
Expand All @@ -30,12 +31,16 @@ let panelCreated = false;
// Instead it relies on the extension to pass filters through.
function syncSavedPreferences() {
const appendComponentStack = getAppendComponentStack();
const suppressDoubleLogging = getsuppressDoubleLogging();
const breakOnConsoleErrors = getBreakOnConsoleErrors();
const componentFilters = getSavedComponentFilters();
chrome.devtools.inspectedWindow.eval(
`window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = ${JSON.stringify(
appendComponentStack,
)};
window.__REACT_DEVTOOLS_SUPPRESS_DOUBLE_LOGGING__ = ${JSON.stringify(
suppressDoubleLogging,
)};
window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ = ${JSON.stringify(
breakOnConsoleErrors,
)};
Expand Down
3 changes: 3 additions & 0 deletions packages/react-devtools-inline/src/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ function startActivation(contentWindow: window) {

const {
appendComponentStack,
suppressDoubleLogging,
breakOnConsoleErrors,
componentFilters,
} = data;

contentWindow.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = appendComponentStack;
contentWindow.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ = breakOnConsoleErrors;
contentWindow.__REACT_DEVTOOLS_SUPPRESS_DOUBLE_LOGGING__ = suppressDoubleLogging;
contentWindow.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = componentFilters;

// TRICKY
Expand All @@ -39,6 +41,7 @@ function startActivation(contentWindow: window) {
if (contentWindow !== window) {
window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = appendComponentStack;
window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ = breakOnConsoleErrors;
window.__REACT_DEVTOOLS_SUPPRESS_DOUBLE_LOGGING__ = suppressDoubleLogging;
window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = componentFilters;
}

Expand Down
2 changes: 2 additions & 0 deletions packages/react-devtools-inline/src/frontend.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
getAppendComponentStack,
getBreakOnConsoleErrors,
getSavedComponentFilters,
getsuppressDoubleLogging,
} from 'react-devtools-shared/src/utils';
import {
MESSAGE_TYPE_GET_SAVED_PREFERENCES,
Expand Down Expand Up @@ -39,6 +40,7 @@ export function initialize(
{
type: MESSAGE_TYPE_SAVED_PREFERENCES,
appendComponentStack: getAppendComponentStack(),
suppressDoubleLogging: getsuppressDoubleLogging(),
breakOnConsoleErrors: getBreakOnConsoleErrors(),
componentFilters: getSavedComponentFilters(),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ describe('console', () => {
appendComponentStack: true,
breakOnWarn: false,
});

expect(fakeConsole.error).toBe(error);
expect(fakeConsole.warn).toBe(warn);
});
Expand Down
2 changes: 2 additions & 0 deletions packages/react-devtools-shared/src/backend/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,9 +446,11 @@ export default class Agent extends EventEmitter<{|
updateConsolePatchSettings = ({
appendComponentStack,
breakOnConsoleErrors,
suppressDoubleLogging,
}: {|
appendComponentStack: boolean,
breakOnConsoleErrors: boolean,
suppressDoubleLogging: boolean,
|}) => {
// If the frontend preference has change,
// or in the case of React Native- if the backend is just finding out the preference-
Expand Down
1 change: 1 addition & 0 deletions packages/react-devtools-shared/src/bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ type NativeStyleEditor_SetValueParams = {|
type UpdateConsolePatchSettingsParams = {|
appendComponentStack: boolean,
breakOnConsoleErrors: boolean,
suppressDoubleLogging: boolean,
|};

type BackendEvents = {|
Expand Down
3 changes: 3 additions & 0 deletions packages/react-devtools-shared/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export const SESSION_STORAGE_RELOAD_AND_PROFILE_KEY =
export const LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS =
'React::DevTools::breakOnConsoleErrors';

export const LOCAL_STORAGE_SHOULD_SUPPRESS_DOUBLE_LOGGING =
'React::DevTools::suppressDoubleLogging';

export const LOCAL_STORAGE_SHOULD_PATCH_CONSOLE_KEY =
'React::DevTools::appendComponentStack';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export default function DebuggingSettings(_: {||}) {
const {
appendComponentStack,
breakOnConsoleErrors,
suppressDoubleLogging,
setsuppressDoubleLogging,
setAppendComponentStack,
setBreakOnConsoleErrors,
} = useContext(SettingsContext);
Expand All @@ -35,7 +37,18 @@ export default function DebuggingSettings(_: {||}) {
Append component stacks to console warnings and errors.
</label>
</div>

<div className={styles.Setting}>
<label>
<input
type="checkbox"
checked={!suppressDoubleLogging}
onChange={({currentTarget}) =>
setsuppressDoubleLogging(!currentTarget.checked)
}
/>{' '}
Suppress console during development-only second render pass
</label>
</div>
<div className={styles.Setting}>
<label>
<input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS,
LOCAL_STORAGE_SHOULD_PATCH_CONSOLE_KEY,
LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY,
LOCAL_STORAGE_SHOULD_SUPPRESS_DOUBLE_LOGGING,
} from 'react-devtools-shared/src/constants';
import {useLocalStorage} from '../hooks';
import {BridgeContext} from '../context';
Expand All @@ -38,6 +39,9 @@ type Context = {|
// Specified as a separate prop so it can trigger a re-render of FixedSizeList.
lineHeight: number,

suppressDoubleLogging: boolean,
setsuppressDoubleLogging: (value: boolean) => void,

appendComponentStack: boolean,
setAppendComponentStack: (value: boolean) => void,

Expand Down Expand Up @@ -79,6 +83,15 @@ function SettingsContextController({
'React::DevTools::theme',
'auto',
);

const [
suppressDoubleLogging,
setsuppressDoubleLogging,
] = useLocalStorage<boolean>(
LOCAL_STORAGE_SHOULD_SUPPRESS_DOUBLE_LOGGING,
false,
);

const [
appendComponentStack,
setAppendComponentStack,
Expand Down Expand Up @@ -147,8 +160,14 @@ function SettingsContextController({
bridge.send('updateConsolePatchSettings', {
appendComponentStack,
breakOnConsoleErrors,
suppressDoubleLogging,
});
}, [bridge, appendComponentStack, breakOnConsoleErrors]);
}, [
bridge,
appendComponentStack,
breakOnConsoleErrors,
suppressDoubleLogging,
]);

useEffect(() => {
bridge.send('setTraceUpdatesEnabled', traceUpdatesEnabled);
Expand All @@ -158,13 +177,15 @@ function SettingsContextController({
() => ({
appendComponentStack,
breakOnConsoleErrors,
suppressDoubleLogging,
displayDensity,
lineHeight:
displayDensity === 'compact'
? COMPACT_LINE_HEIGHT
: COMFORTABLE_LINE_HEIGHT,
setAppendComponentStack,
setBreakOnConsoleErrors,
setsuppressDoubleLogging,
setDisplayDensity,
setTheme,
setTraceUpdatesEnabled,
Expand All @@ -175,8 +196,10 @@ function SettingsContextController({
appendComponentStack,
breakOnConsoleErrors,
displayDensity,
suppressDoubleLogging,
setAppendComponentStack,
setBreakOnConsoleErrors,
setsuppressDoubleLogging,
setDisplayDensity,
setTheme,
setTraceUpdatesEnabled,
Expand Down
20 changes: 20 additions & 0 deletions packages/react-devtools-shared/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
LOCAL_STORAGE_FILTER_PREFERENCES_KEY,
LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS,
LOCAL_STORAGE_SHOULD_PATCH_CONSOLE_KEY,
LOCAL_STORAGE_SHOULD_SUPPRESS_DOUBLE_LOGGING,
} from './constants';
import {ComponentFilterElementType, ElementTypeHostComponent} from './types';
import {
Expand Down Expand Up @@ -261,6 +262,25 @@ export function getBreakOnConsoleErrors(): boolean {
return false;
}

export function setsuppressDoubleLogging(value: boolean): void {
localStorageSetItem(
LOCAL_STORAGE_SHOULD_SUPPRESS_DOUBLE_LOGGING,
JSON.stringify(value),
);
}

export function getsuppressDoubleLogging(): boolean {
try {
const raw = localStorageGetItem(
LOCAL_STORAGE_SHOULD_SUPPRESS_DOUBLE_LOGGING,
);
if (raw != null) {
return JSON.parse(raw);
}
} catch (error) {}
return false;
}

export function setBreakOnConsoleErrors(value: boolean): void {
localStorageSetItem(
LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS,
Expand Down
109 changes: 65 additions & 44 deletions packages/shared/ConsolePatchingDev.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// replaying on render function. This currently only patches the object
// lazily which won't cover if the log function was extracted eagerly.
// We could also eagerly patch the method.
import {canUseDOM} from './ExecutionEnvironment';

let disabledDepth = 0;
let prevLog;
Expand All @@ -20,65 +21,85 @@ let prevError;
let prevGroup;
let prevGroupCollapsed;
let prevGroupEnd;
const {__REACT_DEVTOOLS_SUPPRESS_DOUBLE_LOGGING__: suppressLog} = canUseDOM
? window
: global;

function disabledLog() {}
disabledLog.__reactDisabledLog = true;

function patchConsole() {
/* eslint-disable react-internal/no-production-logging */
prevLog = console.log;
prevInfo = console.info;
prevWarn = console.warn;
prevError = console.error;
prevGroup = console.group;
prevGroupCollapsed = console.groupCollapsed;
prevGroupEnd = console.groupEnd;
// https://github.com/facebook/react/issues/19099
const props = {
configurable: true,
enumerable: true,
value: disabledLog,
writable: true,
};
// $FlowFixMe Flow thinks console is immutable.
Object.defineProperties(console, {
info: props,
log: props,
warn: props,
error: props,
group: props,
groupCollapsed: props,
groupEnd: props,
});
/* eslint-disable react-internal/no-production-logging */
}

function unPatchConsole() {
/* eslint-disable react-internal/no-production-logging */
const props = {
configurable: true,
enumerable: true,
writable: true,
};
// $FlowFixMe Flow thinks console is immutable.
Object.defineProperties(console, {
log: {...props, value: prevLog},
info: {...props, value: prevInfo},
warn: {...props, value: prevWarn},
error: {...props, value: prevError},
group: {...props, value: prevGroup},
groupCollapsed: {...props, value: prevGroupCollapsed},
groupEnd: {...props, value: prevGroupEnd},
});
/* eslint-enable react-internal/no-production-logging */
}

let suppressDoubleLogging = suppressLog;
export function disableLogs(): void {
if (__DEV__) {
if (disabledDepth === 0) {
/* eslint-disable react-internal/no-production-logging */
prevLog = console.log;
prevInfo = console.info;
prevWarn = console.warn;
prevError = console.error;
prevGroup = console.group;
prevGroupCollapsed = console.groupCollapsed;
prevGroupEnd = console.groupEnd;
// https://github.com/facebook/react/issues/19099
const props = {
configurable: true,
enumerable: true,
value: disabledLog,
writable: true,
};
// $FlowFixMe Flow thinks console is immutable.
Object.defineProperties(console, {
info: props,
log: props,
warn: props,
error: props,
group: props,
groupCollapsed: props,
groupEnd: props,
});
/* eslint-enable react-internal/no-production-logging */
if (!suppressDoubleLogging) {
patchConsole();
}
}
disabledDepth++;
}
disabledDepth++;
}

export function reenableLogs(): void {
if (__DEV__) {
disabledDepth--;
if (disabledDepth === 0) {
/* eslint-disable react-internal/no-production-logging */
const props = {
configurable: true,
enumerable: true,
writable: true,
};
// $FlowFixMe Flow thinks console is immutable.
Object.defineProperties(console, {
log: {...props, value: prevLog},
info: {...props, value: prevInfo},
warn: {...props, value: prevWarn},
error: {...props, value: prevError},
group: {...props, value: prevGroup},
groupCollapsed: {...props, value: prevGroupCollapsed},
groupEnd: {...props, value: prevGroupEnd},
});
/* eslint-enable react-internal/no-production-logging */
try {
if (!suppressDoubleLogging) {
unPatchConsole();
}
} finally {
suppressDoubleLogging = suppressLog;
}
}
if (disabledDepth < 0) {
console.error(
Expand Down