Files
react/packages/react-reconciler/src/ReactFiberDevToolsHook.old.js
Luna RuanandGitHub 5b57bc6e31 [Draft] don't patch console during first render (#22308)
Previously, DevTools always overrode the native console to dim or supress StrictMode double logging. It also overrode console.log (in addition to console.error and console.warn). However, this changes the location shown by the browser console, which causes a bad developer experience. There is currently a TC39 proposal that would allow us to extend console without breaking developer experience, but in the meantime this PR changes the StrictMode console override behavior so that we only patch the console during the StrictMode double render so that, during the first render, the location points to developer code rather than our DevTools console code.
2021-09-21 15:00:11 -07:00

215 lines
6.3 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import {
consoleManagedByDevToolsDuringStrictMode,
enableProfilerTimer,
} from 'shared/ReactFeatureFlags';
import type {Fiber, FiberRoot} from './ReactInternalTypes';
import type {ReactNodeList} from 'shared/ReactTypes';
import type {EventPriority} from './ReactEventPriorities.old';
import {DidCapture} from './ReactFiberFlags';
import {
DiscreteEventPriority,
ContinuousEventPriority,
DefaultEventPriority,
IdleEventPriority,
} from './ReactEventPriorities.old';
import {
ImmediatePriority as ImmediateSchedulerPriority,
UserBlockingPriority as UserBlockingSchedulerPriority,
NormalPriority as NormalSchedulerPriority,
IdlePriority as IdleSchedulerPriority,
unstable_yieldValue,
unstable_setDisableYieldValue,
} from './Scheduler';
import {setSuppressWarning} from 'shared/consoleWithStackDev';
import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev';
declare var __REACT_DEVTOOLS_GLOBAL_HOOK__: Object | void;
let rendererID = null;
let injectedHook = null;
let hasLoggedError = false;
export const isDevToolsPresent =
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined';
export function injectInternals(internals: Object): boolean {
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
// No DevTools
return false;
}
const hook = __REACT_DEVTOOLS_GLOBAL_HOOK__;
if (hook.isDisabled) {
// This isn't a real property on the hook, but it can be set to opt out
// of DevTools integration and associated warnings and logs.
// https://github.com/facebook/react/issues/3877
return true;
}
if (!hook.supportsFiber) {
if (__DEV__) {
console.error(
'The installed version of React DevTools is too old and will not work ' +
'with the current version of React. Please update React DevTools. ' +
'https://reactjs.org/link/react-devtools',
);
}
// DevTools exists, even though it doesn't support Fiber.
return true;
}
try {
rendererID = hook.inject(internals);
// We have successfully injected, so now it is safe to set up hooks.
injectedHook = hook;
} catch (err) {
// Catch all errors because it is unsafe to throw during initialization.
if (__DEV__) {
console.error('React instrumentation encountered an error: %s.', err);
}
}
if (hook.checkDCE) {
// This is the real DevTools.
return true;
} else {
// This is likely a hook installed by Fast Refresh runtime.
return false;
}
}
export function onScheduleRoot(root: FiberRoot, children: ReactNodeList) {
if (__DEV__) {
if (
injectedHook &&
typeof injectedHook.onScheduleFiberRoot === 'function'
) {
try {
injectedHook.onScheduleFiberRoot(rendererID, root, children);
} catch (err) {
if (__DEV__ && !hasLoggedError) {
hasLoggedError = true;
console.error('React instrumentation encountered an error: %s', err);
}
}
}
}
}
export function onCommitRoot(root: FiberRoot, eventPriority: EventPriority) {
if (injectedHook && typeof injectedHook.onCommitFiberRoot === 'function') {
try {
const didError = (root.current.flags & DidCapture) === DidCapture;
if (enableProfilerTimer) {
let schedulerPriority;
switch (eventPriority) {
case DiscreteEventPriority:
schedulerPriority = ImmediateSchedulerPriority;
break;
case ContinuousEventPriority:
schedulerPriority = UserBlockingSchedulerPriority;
break;
case DefaultEventPriority:
schedulerPriority = NormalSchedulerPriority;
break;
case IdleEventPriority:
schedulerPriority = IdleSchedulerPriority;
break;
default:
schedulerPriority = NormalSchedulerPriority;
break;
}
injectedHook.onCommitFiberRoot(
rendererID,
root,
schedulerPriority,
didError,
);
} else {
injectedHook.onCommitFiberRoot(rendererID, root, undefined, didError);
}
} catch (err) {
if (__DEV__) {
if (!hasLoggedError) {
hasLoggedError = true;
console.error('React instrumentation encountered an error: %s', err);
}
}
}
}
}
export function onPostCommitRoot(root: FiberRoot) {
if (
injectedHook &&
typeof injectedHook.onPostCommitFiberRoot === 'function'
) {
try {
injectedHook.onPostCommitFiberRoot(rendererID, root);
} catch (err) {
if (__DEV__) {
if (!hasLoggedError) {
hasLoggedError = true;
console.error('React instrumentation encountered an error: %s', err);
}
}
}
}
}
export function onCommitUnmount(fiber: Fiber) {
if (injectedHook && typeof injectedHook.onCommitFiberUnmount === 'function') {
try {
injectedHook.onCommitFiberUnmount(rendererID, fiber);
} catch (err) {
if (__DEV__) {
if (!hasLoggedError) {
hasLoggedError = true;
console.error('React instrumentation encountered an error: %s', err);
}
}
}
}
}
export function setIsStrictModeForDevtools(newIsStrictMode: boolean) {
if (consoleManagedByDevToolsDuringStrictMode) {
if (typeof unstable_yieldValue === 'function') {
// We're in a test because Scheduler.unstable_yieldValue only exists
// in SchedulerMock. To reduce the noise in strict mode tests,
// suppress warnings and disable scheduler yielding during the double render
unstable_setDisableYieldValue(newIsStrictMode);
setSuppressWarning(newIsStrictMode);
}
if (injectedHook && typeof injectedHook.setStrictMode === 'function') {
try {
injectedHook.setStrictMode(rendererID, newIsStrictMode);
} catch (err) {
if (__DEV__) {
if (!hasLoggedError) {
hasLoggedError = true;
console.error(
'React instrumentation encountered an error: %s',
err,
);
}
}
}
}
} else {
if (newIsStrictMode) {
disableLogs();
} else {
reenableLogs();
}
}
}