diff --git a/packages/react-dom/src/client/ReactDOMFB.js b/packages/react-dom/src/client/ReactDOMFB.js index aa7c7dbf64459..8b846cf4a9190 100644 --- a/packages/react-dom/src/client/ReactDOMFB.js +++ b/packages/react-dom/src/client/ReactDOMFB.js @@ -9,8 +9,6 @@ import * as ReactFiberTreeReflection from 'react-reconciler/reflection'; import * as ReactInstanceMap from 'shared/ReactInstanceMap'; -// TODO: direct imports like some-package/src/* are bad. Fix me. -import * as ReactFiberErrorLogger from 'react-reconciler/src/ReactFiberErrorLogger'; import ReactErrorUtils from 'shared/ReactErrorUtils'; import {addUserTimingListener} from 'shared/ReactFeatureFlags'; @@ -25,7 +23,6 @@ Object.assign( // These are real internal dependencies that are trickier to remove: ReactBrowserEventEmitter, ReactErrorUtils, - ReactFiberErrorLogger, ReactFiberTreeReflection, ReactDOMComponentTree, ReactInstanceMap, diff --git a/packages/react-native-renderer/src/ReactNativeRenderer.js b/packages/react-native-renderer/src/ReactNativeRenderer.js index 8b6dca0d55187..89ec15c3c0488 100644 --- a/packages/react-native-renderer/src/ReactNativeRenderer.js +++ b/packages/react-native-renderer/src/ReactNativeRenderer.js @@ -12,8 +12,6 @@ import type {ReactNodeList} from 'shared/ReactTypes'; import './ReactNativeInjection'; -// TODO: direct imports like some-package/src/* are bad. Fix me. -import * as ReactFiberErrorLogger from 'react-reconciler/src/ReactFiberErrorLogger'; import * as ReactPortal from 'react-reconciler/src/ReactPortal'; import * as ReactGenericBatching from 'events/ReactGenericBatching'; import TouchHistoryMath from 'events/TouchHistoryMath'; @@ -22,7 +20,6 @@ import ReactVersion from 'shared/ReactVersion'; // Module provided by RN: import UIManager from 'UIManager'; -import {showDialog} from './ReactNativeFiberErrorDialog'; import NativeMethodsMixin from './NativeMethodsMixin'; import ReactNativeBridgeEventPlugin from './ReactNativeBridgeEventPlugin'; import ReactNativeComponent from './ReactNativeComponent'; @@ -40,10 +37,6 @@ ReactGenericBatching.injection.injectFiberBatchedUpdates( const roots = new Map(); -// Intercept lifecycle errors and ensure they are shown with the correct stack -// trace within the native redbox component. -ReactFiberErrorLogger.injection.injectDialog(showDialog); - const ReactNativeRenderer: ReactNativeType = { NativeComponent: ReactNativeComponent, diff --git a/packages/react-reconciler/src/ReactFiberErrorDialog.js b/packages/react-reconciler/src/ReactFiberErrorDialog.js new file mode 100644 index 0000000000000..8459be5bad8c3 --- /dev/null +++ b/packages/react-reconciler/src/ReactFiberErrorDialog.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import type {CapturedError} from './ReactFiberScheduler'; + +// This module is forked in different environments. +// By default, return `true` to log errors to the console. +// Forks can return `false` if this isn't desirable. +export function showErrorDialog(capturedError: CapturedError): boolean { + return true; +} diff --git a/packages/react-reconciler/src/ReactFiberErrorLogger.js b/packages/react-reconciler/src/ReactFiberErrorLogger.js index 06cc1678479b0..d9bf2bb950cea 100644 --- a/packages/react-reconciler/src/ReactFiberErrorLogger.js +++ b/packages/react-reconciler/src/ReactFiberErrorLogger.js @@ -9,16 +9,12 @@ import type {CapturedError} from './ReactFiberScheduler'; -import invariant from 'fbjs/lib/invariant'; - -const defaultShowDialog = (capturedError: CapturedError) => true; - -let showDialog = defaultShowDialog; +import {showErrorDialog} from './ReactFiberErrorDialog'; export function logCapturedError(capturedError: CapturedError): void { - const logError = showDialog(capturedError); + const logError = showErrorDialog(capturedError); - // Allow injected showDialog() to prevent default console.error logging. + // Allow injected showErrorDialog() to prevent default console.error logging. // This enables renderers like ReactNative to better manage redbox behavior. if (logError === false) { return; @@ -78,21 +74,3 @@ export function logCapturedError(capturedError: CapturedError): void { console.error(error); } } - -export const injection = { - /** - * Display custom dialog for lifecycle errors. - * Return false to prevent default behavior of logging to console.error. - */ - injectDialog(fn: (e: CapturedError) => boolean) { - invariant( - showDialog === defaultShowDialog, - 'The custom dialog was already injected.', - ); - invariant( - typeof fn === 'function', - 'Injected showDialog() must be a function.', - ); - showDialog = fn; - }, -}; diff --git a/packages/react-native-renderer/src/ReactNativeFiberErrorDialog.js b/packages/react-reconciler/src/forks/ReactFiberErrorDialog.native.js similarity index 90% rename from packages/react-native-renderer/src/ReactNativeFiberErrorDialog.js rename to packages/react-reconciler/src/forks/ReactFiberErrorDialog.native.js index 1c444ccbd0b2a..40d3d6460f8c1 100644 --- a/packages/react-native-renderer/src/ReactNativeFiberErrorDialog.js +++ b/packages/react-reconciler/src/forks/ReactFiberErrorDialog.native.js @@ -7,7 +7,7 @@ * @flow */ -import type {CapturedError} from 'react-reconciler/src/ReactFiberScheduler'; +import type {CapturedError} from '../ReactFiberScheduler'; // Module provided by RN: import ExceptionsManager from 'ExceptionsManager'; @@ -16,7 +16,7 @@ import ExceptionsManager from 'ExceptionsManager'; * Intercept lifecycle errors and ensure they are shown with the correct stack * trace within the native redbox component. */ -export function showDialog(capturedError: CapturedError): boolean { +export function showErrorDialog(capturedError: CapturedError): boolean { const {componentStack, error} = capturedError; let errorToHandle: Error; diff --git a/packages/react-reconciler/src/forks/ReactFiberErrorDialog.www.js b/packages/react-reconciler/src/forks/ReactFiberErrorDialog.www.js new file mode 100644 index 0000000000000..80546ec1987ea --- /dev/null +++ b/packages/react-reconciler/src/forks/ReactFiberErrorDialog.www.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import type {CapturedError} from '../ReactFiberScheduler'; + +// Provided by www +const ReactFiberErrorDialogWWW = require('ReactFiberErrorDialog'); + +export function showErrorDialog(capturedError: CapturedError): boolean { + return ReactFiberErrorDialogWWW.showErrorDialog(capturedError); +} diff --git a/packages/react-rt-renderer/src/ReactNativeRT.js b/packages/react-rt-renderer/src/ReactNativeRT.js index 996e2ba147d30..97598139838ca 100644 --- a/packages/react-rt-renderer/src/ReactNativeRT.js +++ b/packages/react-rt-renderer/src/ReactNativeRT.js @@ -19,9 +19,6 @@ import type {ReactNodeList} from 'shared/ReactTypes'; import 'InitializeCore'; import './ReactNativeRTEventEmitter'; -// TODO: direct imports like some-package/src/* are bad. Fix me. -import * as ReactFiberErrorLogger from 'react-reconciler/src/ReactFiberErrorLogger'; -import {showDialog} from 'react-native-renderer/src/ReactNativeFiberErrorDialog'; import * as ReactPortal from 'react-reconciler/src/ReactPortal'; import * as ReactGenericBatching from 'events/ReactGenericBatching'; import ReactVersion from 'shared/ReactVersion'; @@ -36,10 +33,6 @@ ReactGenericBatching.injection.injectFiberBatchedUpdates( const roots = new Map(); -// Intercept lifecycle errors and ensure they are shown with the correct stack -// trace within the native redbox component. -ReactFiberErrorLogger.injection.injectDialog(showDialog); - const ReactNativeRTFiber: ReactNativeRTType = { render(element: React$Element, containerTag: any, callback: ?Function) { let root = roots.get(containerTag); diff --git a/scripts/flow/environment.js b/scripts/flow/environment.js index f06d9e2929e9f..ca9ab99c1b256 100644 --- a/scripts/flow/environment.js +++ b/scripts/flow/environment.js @@ -13,7 +13,14 @@ declare var __REACT_DEVTOOLS_GLOBAL_HOOK__: any; /*?{ inject: ?((stuff: Object) => void) };*/ -// ReactFeatureFlags rollup shim for www imports the www implementation. +// ReactFeatureFlags www fork declare module 'ReactFeatureFlags' { declare module.exports: any; } + +// ReactFiberErrorDialog www fork +declare module 'ReactFiberErrorDialog' { + declare module.exports: { + showErrorDialog: (error: mixed) => boolean, + }; +} diff --git a/scripts/rollup/forks.js b/scripts/rollup/forks.js index 0c3845353d008..920b6a49e4ffc 100644 --- a/scripts/rollup/forks.js +++ b/scripts/rollup/forks.js @@ -6,6 +6,8 @@ const UMD_DEV = bundleTypes.UMD_DEV; const UMD_PROD = bundleTypes.UMD_PROD; const FB_DEV = bundleTypes.FB_DEV; const FB_PROD = bundleTypes.FB_PROD; +const RN_DEV = bundleTypes.RN_DEV; +const RN_PROD = bundleTypes.RN_PROD; // If you need to replace a file with another file for a specific environment, // add it to this list with the logic for choosing the right replacement. @@ -66,6 +68,28 @@ const forks = Object.freeze({ return null; } }, + + // Different behavior for caught errors. + 'react-reconciler/src/ReactFiberErrorDialog': (bundleType, entry) => { + switch (bundleType) { + case FB_DEV: + case FB_PROD: + // Use the www fork which shows an error dialog. + return 'react-reconciler/src/forks/ReactFiberErrorDialog.www.js'; + case RN_DEV: + case RN_PROD: + switch (entry) { + case 'react-native-renderer': + case 'react-rt-renderer': + // Use the RN fork which plays well with redbox. + return 'react-reconciler/src/forks/ReactFiberErrorDialog.native.js'; + default: + return null; + } + default: + return null; + } + }, }); module.exports = forks; diff --git a/scripts/rollup/shims/facebook-www/ReactFiberErrorLogger.js b/scripts/rollup/shims/facebook-www/ReactFiberErrorLogger.js deleted file mode 100644 index 48cf59fb80ff0..0000000000000 --- a/scripts/rollup/shims/facebook-www/ReactFiberErrorLogger.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactFiberErrorLogger - */ - -'use strict'; - -const { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, -} = require('ReactDOM-fb'); - -module.exports = - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactFiberErrorLogger;