mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
DevTools: Add break-on-warn feature (#19048)
This commit adds a new tab to the Settings modal: Debugging This new tab has the append component stacks feature and a new one: break on warn This new feature adds a debugger statement into the console override
This commit is contained in:
+11
-5
@@ -161,8 +161,8 @@ export default class Agent extends EventEmitter<{|
|
||||
);
|
||||
bridge.addListener('shutdown', this.shutdown);
|
||||
bridge.addListener(
|
||||
'updateAppendComponentStack',
|
||||
this.updateAppendComponentStack,
|
||||
'updateConsolePatchSettings',
|
||||
this.updateConsolePatchSettings,
|
||||
);
|
||||
bridge.addListener('updateComponentFilters', this.updateComponentFilters);
|
||||
bridge.addListener('viewAttributeSource', this.viewAttributeSource);
|
||||
@@ -443,13 +443,19 @@ export default class Agent extends EventEmitter<{|
|
||||
}
|
||||
};
|
||||
|
||||
updateAppendComponentStack = (appendComponentStack: boolean) => {
|
||||
updateConsolePatchSettings = ({
|
||||
appendComponentStack,
|
||||
breakOnConsoleErrors,
|
||||
}: {|
|
||||
appendComponentStack: boolean,
|
||||
breakOnConsoleErrors: boolean,
|
||||
|}) => {
|
||||
// If the frontend preference has change,
|
||||
// or in the case of React Native- if the backend is just finding out the preference-
|
||||
// then install or uninstall the console overrides.
|
||||
// It's safe to call these methods multiple times, so we don't need to worry about that.
|
||||
if (appendComponentStack) {
|
||||
patchConsole();
|
||||
if (appendComponentStack || breakOnConsoleErrors) {
|
||||
patchConsole({appendComponentStack, breakOnConsoleErrors});
|
||||
} else {
|
||||
unpatchConsole();
|
||||
}
|
||||
|
||||
+62
-30
@@ -80,9 +80,25 @@ export function registerRenderer(renderer: ReactRenderer): void {
|
||||
}
|
||||
}
|
||||
|
||||
const consoleSettingsRef = {
|
||||
appendComponentStack: false,
|
||||
breakOnConsoleErrors: false,
|
||||
};
|
||||
|
||||
// Patches whitelisted console methods to append component stack for the current fiber.
|
||||
// Call unpatch() to remove the injected behavior.
|
||||
export function patch(): void {
|
||||
export function patch({
|
||||
appendComponentStack,
|
||||
breakOnConsoleErrors,
|
||||
}: {
|
||||
appendComponentStack: boolean,
|
||||
breakOnConsoleErrors: boolean,
|
||||
}): void {
|
||||
// Settings may change after we've patched the console.
|
||||
// Using a shared ref allows the patch function to read the latest values.
|
||||
consoleSettingsRef.appendComponentStack = appendComponentStack;
|
||||
consoleSettingsRef.breakOnConsoleErrors = breakOnConsoleErrors;
|
||||
|
||||
if (unpatchFn !== null) {
|
||||
// Don't patch twice.
|
||||
return;
|
||||
@@ -105,40 +121,56 @@ export function patch(): void {
|
||||
targetConsole[method]);
|
||||
|
||||
const overrideMethod = (...args) => {
|
||||
try {
|
||||
// If we are ever called with a string that already has a component stack, e.g. a React error/warning,
|
||||
// don't append a second stack.
|
||||
const lastArg = args.length > 0 ? args[args.length - 1] : null;
|
||||
const alreadyHasComponentStack =
|
||||
lastArg !== null &&
|
||||
(PREFIX_REGEX.test(lastArg) ||
|
||||
ROW_COLUMN_NUMBER_REGEX.test(lastArg));
|
||||
const latestAppendComponentStack =
|
||||
consoleSettingsRef.appendComponentStack;
|
||||
const latestBreakOnConsoleErrors =
|
||||
consoleSettingsRef.breakOnConsoleErrors;
|
||||
|
||||
if (!alreadyHasComponentStack) {
|
||||
// If there's a component stack for at least one of the injected renderers, append it.
|
||||
// We don't handle the edge case of stacks for more than one (e.g. interleaved renderers?)
|
||||
// eslint-disable-next-line no-for-of-loops/no-for-of-loops
|
||||
for (const {
|
||||
currentDispatcherRef,
|
||||
getCurrentFiber,
|
||||
workTagMap,
|
||||
} of injectedRenderers.values()) {
|
||||
const current: ?Fiber = getCurrentFiber();
|
||||
if (current != null) {
|
||||
const componentStack = getStackByFiberInDevAndProd(
|
||||
workTagMap,
|
||||
current,
|
||||
currentDispatcherRef,
|
||||
);
|
||||
if (componentStack !== '') {
|
||||
args.push(componentStack);
|
||||
if (latestAppendComponentStack) {
|
||||
try {
|
||||
// If we are ever called with a string that already has a component stack, e.g. a React error/warning,
|
||||
// don't append a second stack.
|
||||
const lastArg = args.length > 0 ? args[args.length - 1] : null;
|
||||
const alreadyHasComponentStack =
|
||||
lastArg !== null &&
|
||||
(PREFIX_REGEX.test(lastArg) ||
|
||||
ROW_COLUMN_NUMBER_REGEX.test(lastArg));
|
||||
|
||||
if (!alreadyHasComponentStack) {
|
||||
// If there's a component stack for at least one of the injected renderers, append it.
|
||||
// We don't handle the edge case of stacks for more than one (e.g. interleaved renderers?)
|
||||
// eslint-disable-next-line no-for-of-loops/no-for-of-loops
|
||||
for (const {
|
||||
currentDispatcherRef,
|
||||
getCurrentFiber,
|
||||
workTagMap,
|
||||
} of injectedRenderers.values()) {
|
||||
const current: ?Fiber = getCurrentFiber();
|
||||
if (current != null) {
|
||||
const componentStack = getStackByFiberInDevAndProd(
|
||||
workTagMap,
|
||||
current,
|
||||
currentDispatcherRef,
|
||||
);
|
||||
if (componentStack !== '') {
|
||||
args.push(componentStack);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Don't let a DevTools or React internal error interfere with logging.
|
||||
}
|
||||
} catch (error) {
|
||||
// Don't let a DevTools or React internal error interfere with logging.
|
||||
}
|
||||
|
||||
if (latestBreakOnConsoleErrors) {
|
||||
// --- Welcome to debugging with React DevTools ---
|
||||
// This debugger statement means that you've enabled the "break on warnings" feature.
|
||||
// Use the browser's Call Stack panel to step out of this override function-
|
||||
// to where the original warning or error was logged.
|
||||
// eslint-disable-next-line no-debugger
|
||||
debugger;
|
||||
}
|
||||
|
||||
originalMethod(...args);
|
||||
|
||||
+10
-3
@@ -430,11 +430,18 @@ export function attach(
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
registerRendererWithConsole(renderer);
|
||||
|
||||
// The renderer interface can't read this preference directly,
|
||||
// The renderer interface can't read these preferences directly,
|
||||
// because it is stored in localStorage within the context of the extension.
|
||||
// It relies on the extension to pass the preference through via the global.
|
||||
if (window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ !== false) {
|
||||
patchConsole();
|
||||
const appendComponentStack =
|
||||
window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ !== false;
|
||||
const breakOnConsoleErrors =
|
||||
window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ === true;
|
||||
if (appendComponentStack || breakOnConsoleErrors) {
|
||||
patchConsole({
|
||||
appendComponentStack,
|
||||
breakOnConsoleErrors,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user