diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index 84ef45f08b0..878971aa137 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -28,196 +28,21 @@ const startTime = global.nativePerformanceNow != null ? global.nativePerformanceNow() : null; -const {polyfillObjectProperty, polyfillGlobal} = require('PolyfillFunctions'); - -if (global.GLOBAL === undefined) { - global.GLOBAL = global; -} - -if (global.window === undefined) { - global.window = global; -} - -// Set up collections -const _shouldPolyfillCollection = require('_shouldPolyfillES6Collection'); -if (_shouldPolyfillCollection('Map')) { - polyfillGlobal('Map', () => require('Map')); -} -if (_shouldPolyfillCollection('Set')) { - polyfillGlobal('Set', () => require('Set')); -} - -// Set up process -global.process = global.process || {}; -global.process.env = global.process.env || {}; -if (!global.process.env.NODE_ENV) { - global.process.env.NODE_ENV = __DEV__ ? 'development' : 'production'; -} - -// Setup the Systrace profiling hooks if necessary -if (global.__RCTProfileIsProfiling) { - const Systrace = require('Systrace'); - Systrace.installReactHook(); - Systrace.setEnabled(true); -} - -// Set up console -const ExceptionsManager = require('ExceptionsManager'); -ExceptionsManager.installConsoleErrorReporter(); - -// Set up error handler -if (!global.__fbDisableExceptionsManager) { - const handleError = (e, isFatal) => { - try { - ExceptionsManager.handleException(e, isFatal); - } catch (ee) { - console.log('Failed to print error: ', ee.message); - throw e; - } - }; - - const ErrorUtils = require('ErrorUtils'); - ErrorUtils.setGlobalHandler(handleError); -} - -// Check for compatibility between the JS and native code -const ReactNativeVersionCheck = require('ReactNativeVersionCheck'); -ReactNativeVersionCheck.checkVersions(); - -// Set up Promise -// The native Promise implementation throws the following error: -// ERROR: Event loop not supported. -polyfillGlobal('Promise', () => require('Promise')); - -// Set up regenerator. -polyfillGlobal('regeneratorRuntime', () => { - // The require just sets up the global, so make sure when we first - // invoke it the global does not exist - delete global.regeneratorRuntime; - - // regenerator-runtime/runtime exports the regeneratorRuntime object, so we - // can return it safely. - return require('regenerator-runtime/runtime'); -}); - -// Set up timers -const defineLazyTimer = name => { - polyfillGlobal(name, () => require('JSTimers')[name]); -}; -defineLazyTimer('setTimeout'); -defineLazyTimer('setInterval'); -defineLazyTimer('setImmediate'); -defineLazyTimer('clearTimeout'); -defineLazyTimer('clearInterval'); -defineLazyTimer('clearImmediate'); -defineLazyTimer('requestAnimationFrame'); -defineLazyTimer('cancelAnimationFrame'); -defineLazyTimer('requestIdleCallback'); -defineLazyTimer('cancelIdleCallback'); - -// Set up XHR -// The native XMLHttpRequest in Chrome dev tools is CORS aware and won't -// let you fetch anything from the internet -polyfillGlobal('XMLHttpRequest', () => require('XMLHttpRequest')); -polyfillGlobal('FormData', () => require('FormData')); - -polyfillGlobal('fetch', () => require('fetch').fetch); -polyfillGlobal('Headers', () => require('fetch').Headers); -polyfillGlobal('Request', () => require('fetch').Request); -polyfillGlobal('Response', () => require('fetch').Response); -polyfillGlobal('WebSocket', () => require('WebSocket')); -polyfillGlobal('Blob', () => require('Blob')); -polyfillGlobal('File', () => require('File')); -polyfillGlobal('FileReader', () => require('FileReader')); -polyfillGlobal('URL', () => require('URL')); - -// Set up alert -if (!global.alert) { - global.alert = function(text) { - // Require Alert on demand. Requiring it too early can lead to issues - // with things like Platform not being fully initialized. - require('Alert').alert('Alert', '' + text); - }; -} - -// Set up Geolocation -let navigator = global.navigator; -if (navigator === undefined) { - global.navigator = navigator = {}; -} - -// see https://github.com/facebook/react-native/issues/10881 -polyfillObjectProperty(navigator, 'product', () => 'ReactNative'); -polyfillObjectProperty(navigator, 'geolocation', () => require('Geolocation')); - -// Just to make sure the JS gets packaged up. Wait until the JS environment has -// been initialized before requiring them. -const BatchedBridge = require('BatchedBridge'); -BatchedBridge.registerLazyCallableModule('Systrace', () => require('Systrace')); -BatchedBridge.registerLazyCallableModule('JSTimers', () => require('JSTimers')); -BatchedBridge.registerLazyCallableModule('HeapCapture', () => - require('HeapCapture'), -); -BatchedBridge.registerLazyCallableModule('SamplingProfiler', () => - require('SamplingProfiler'), -); -BatchedBridge.registerLazyCallableModule('RCTLog', () => require('RCTLog')); -BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () => - require('RCTDeviceEventEmitter'), -); -BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () => - require('RCTNativeAppEventEmitter'), -); -BatchedBridge.registerLazyCallableModule('PerformanceLogger', () => - require('PerformanceLogger'), -); -BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () => - require('JSDevSupportModule'), -); - -global.__fetchSegment = function( - segmentId: number, - options: {|+otaBuildNumber: ?string|}, - callback: (?Error) => void, -) { - const {SegmentFetcher} = require('NativeModules'); - if (!SegmentFetcher) { - throw new Error( - 'SegmentFetcher is missing. Please ensure that it is ' + - 'included as a NativeModule.', - ); - } - - SegmentFetcher.fetchSegment( - segmentId, - options, - (errorObject: ?{message: string, code: string}) => { - if (errorObject) { - const error = new Error(errorObject.message); - (error: any).code = errorObject.code; - callback(error); - } - - callback(null); - }, - ); -}; - -// Set up devtools +require('setUpGlobals'); +require('polyfillES6Collections'); +require('setUpSystrace'); +require('setUpErrorHandling'); +require('checkNativeVersion'); +require('polyfillPromise'); +require('setUpRegeneratorRuntime'); +require('setUpTimers'); +require('setUpXHR'); +require('setUpAlert'); +require('setUpGeolocation'); +require('setUpBatchedBridge'); +require('setUpSegmentFetcher'); if (__DEV__) { - if (!global.__RCTProfileIsProfiling) { - BatchedBridge.registerCallableModule('HMRClient', require('HMRClient')); - - // not when debugging in chrome - // TODO(t12832058) This check is broken - if (!window.document) { - require('setupDevtools'); - } - - // Set up inspector - const JSInspector = require('JSInspector'); - JSInspector.registerAgent(require('NetworkAgent')); - } + require('setUpDeveloperTools'); } if (startTime != null) { diff --git a/Libraries/Core/checkNativeVersion.js b/Libraries/Core/checkNativeVersion.js new file mode 100644 index 00000000000..36a8b40ac53 --- /dev/null +++ b/Libraries/Core/checkNativeVersion.js @@ -0,0 +1,17 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +/** + * Check for compatibility between the JS and native code. + * You can use this module directly, or just require InitializeCore. + */ +const ReactNativeVersionCheck = require('ReactNativeVersionCheck'); +ReactNativeVersionCheck.checkVersions(); diff --git a/Libraries/Core/polyfillES6Collections.js b/Libraries/Core/polyfillES6Collections.js new file mode 100644 index 00000000000..ca1ee798c73 --- /dev/null +++ b/Libraries/Core/polyfillES6Collections.js @@ -0,0 +1,25 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('PolyfillFunctions'); + +/** + * Polyfill ES6 collections (Map and Set). + * If you don't need these polyfills, don't use InitializeCore; just directly + * require the modules you need from InitializeCore for setup. + */ +const _shouldPolyfillCollection = require('_shouldPolyfillES6Collection'); +if (_shouldPolyfillCollection('Map')) { + polyfillGlobal('Map', () => require('Map')); +} +if (_shouldPolyfillCollection('Set')) { + polyfillGlobal('Set', () => require('Set')); +} diff --git a/Libraries/Core/polyfillPromise.js b/Libraries/Core/polyfillPromise.js new file mode 100644 index 00000000000..cefa5bff2ac --- /dev/null +++ b/Libraries/Core/polyfillPromise.js @@ -0,0 +1,21 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('PolyfillFunctions'); + +/** + * Set up Promise. The native Promise implementation throws the following error: + * ERROR: Event loop not supported. + * + * If you don't need these polyfills, don't use InitializeCore; just directly + * require the modules you need from InitializeCore for setup. + */ +polyfillGlobal('Promise', () => require('Promise')); diff --git a/Libraries/Core/setUpAlert.js b/Libraries/Core/setUpAlert.js new file mode 100644 index 00000000000..0b2bdc9f6a5 --- /dev/null +++ b/Libraries/Core/setUpAlert.js @@ -0,0 +1,22 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +/** + * Set up alert(). + * You can use this module directly, or just require InitializeCore. + */ +if (!global.alert) { + global.alert = function(text) { + // Require Alert on demand. Requiring it too early can lead to issues + // with things like Platform not being fully initialized. + require('Alert').alert('Alert', '' + text); + }; +} diff --git a/Libraries/Core/setUpBatchedBridge.js b/Libraries/Core/setUpBatchedBridge.js new file mode 100644 index 00000000000..fd936bf5042 --- /dev/null +++ b/Libraries/Core/setUpBatchedBridge.js @@ -0,0 +1,42 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +/** + * Set up the BatchedBridge. This must be done after the other steps in + * InitializeCore to ensure that the JS environment has been initialized. + * You can use this module directly, or just require InitializeCore. + */ +const BatchedBridge = require('BatchedBridge'); +BatchedBridge.registerLazyCallableModule('Systrace', () => require('Systrace')); +BatchedBridge.registerLazyCallableModule('JSTimers', () => require('JSTimers')); +BatchedBridge.registerLazyCallableModule('HeapCapture', () => + require('HeapCapture'), +); +BatchedBridge.registerLazyCallableModule('SamplingProfiler', () => + require('SamplingProfiler'), +); +BatchedBridge.registerLazyCallableModule('RCTLog', () => require('RCTLog')); +BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () => + require('RCTDeviceEventEmitter'), +); +BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () => + require('RCTNativeAppEventEmitter'), +); +BatchedBridge.registerLazyCallableModule('PerformanceLogger', () => + require('PerformanceLogger'), +); +BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () => + require('JSDevSupportModule'), +); + +if (__DEV__ && !global.__RCTProfileIsProfiling) { + BatchedBridge.registerCallableModule('HMRClient', require('HMRClient')); +} diff --git a/Libraries/Core/setUpDeveloperTools.js b/Libraries/Core/setUpDeveloperTools.js new file mode 100644 index 00000000000..2ee713da0b4 --- /dev/null +++ b/Libraries/Core/setUpDeveloperTools.js @@ -0,0 +1,28 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +/** + * Sets up developer tools for React Native. + * You can use this module directly, or just require InitializeCore. + */ +if (__DEV__) { + if (!global.__RCTProfileIsProfiling) { + // not when debugging in chrome + // TODO(t12832058) This check is broken + if (!window.document) { + require('setupDevtools'); + } + + // Set up inspector + const JSInspector = require('JSInspector'); + JSInspector.registerAgent(require('NetworkAgent')); + } +} diff --git a/Libraries/Core/setUpErrorHandling.js b/Libraries/Core/setUpErrorHandling.js new file mode 100644 index 00000000000..7a9c566905d --- /dev/null +++ b/Libraries/Core/setUpErrorHandling.js @@ -0,0 +1,32 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +/** + * Sets up the console and exception handling (redbox) for React Native. + * You can use this module directly, or just require InitializeCore. + */ +const ExceptionsManager = require('ExceptionsManager'); +ExceptionsManager.installConsoleErrorReporter(); + +// Set up error handler +if (!global.__fbDisableExceptionsManager) { + const handleError = (e, isFatal) => { + try { + ExceptionsManager.handleException(e, isFatal); + } catch (ee) { + console.log('Failed to print error: ', ee.message); + throw e; + } + }; + + const ErrorUtils = require('ErrorUtils'); + ErrorUtils.setGlobalHandler(handleError); +} diff --git a/Libraries/Core/setUpGeolocation.js b/Libraries/Core/setUpGeolocation.js new file mode 100644 index 00000000000..fd68182bce6 --- /dev/null +++ b/Libraries/Core/setUpGeolocation.js @@ -0,0 +1,25 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +const {polyfillObjectProperty} = require('PolyfillFunctions'); + +/** + * Set up Geolocation. + * You can use this module directly, or just require InitializeCore. + */ +let navigator = global.navigator; +if (navigator === undefined) { + global.navigator = navigator = {}; +} + +// see https://github.com/facebook/react-native/issues/10881 +polyfillObjectProperty(navigator, 'product', () => 'ReactNative'); +polyfillObjectProperty(navigator, 'geolocation', () => require('Geolocation')); diff --git a/Libraries/Core/setUpGlobals.js b/Libraries/Core/setUpGlobals.js new file mode 100644 index 00000000000..0310f3c2bcf --- /dev/null +++ b/Libraries/Core/setUpGlobals.js @@ -0,0 +1,29 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +/** + * Sets up global variables for React Native. + * You can use this module directly, or just require InitializeCore. + */ +if (global.GLOBAL === undefined) { + global.GLOBAL = global; +} + +if (global.window === undefined) { + global.window = global; +} + +// Set up process +global.process = global.process || {}; +global.process.env = global.process.env || {}; +if (!global.process.env.NODE_ENV) { + global.process.env.NODE_ENV = __DEV__ ? 'development' : 'production'; +} diff --git a/Libraries/Core/setUpRegeneratorRuntime.js b/Libraries/Core/setUpRegeneratorRuntime.js new file mode 100644 index 00000000000..26fb440c6d2 --- /dev/null +++ b/Libraries/Core/setUpRegeneratorRuntime.js @@ -0,0 +1,26 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('PolyfillFunctions'); + +/** + * Set up regenerator. + * You can use this module directly, or just require InitializeCore. + */ +polyfillGlobal('regeneratorRuntime', () => { + // The require just sets up the global, so make sure when we first + // invoke it the global does not exist + delete global.regeneratorRuntime; + + // regenerator-runtime/runtime exports the regeneratorRuntime object, so we + // can return it safely. + return require('regenerator-runtime/runtime'); // flowlint-line untyped-import:off +}); diff --git a/Libraries/Core/setUpSegmentFetcher.js b/Libraries/Core/setUpSegmentFetcher.js new file mode 100644 index 00000000000..440caf380f3 --- /dev/null +++ b/Libraries/Core/setUpSegmentFetcher.js @@ -0,0 +1,42 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +/** + * Set up SegmentFetcher. + * You can use this module directly, or just require InitializeCore. + */ +global.__fetchSegment = function( + segmentId: number, + options: {|+otaBuildNumber: ?string|}, + callback: (?Error) => void, +) { + const {SegmentFetcher} = require('NativeModules'); + if (!SegmentFetcher) { + throw new Error( + 'SegmentFetcher is missing. Please ensure that it is ' + + 'included as a NativeModule.', + ); + } + + SegmentFetcher.fetchSegment( + segmentId, + options, + (errorObject: ?{message: string, code: string}) => { + if (errorObject) { + const error = new Error(errorObject.message); + (error: any).code = errorObject.code; // flowlint-line unclear-type: off + callback(error); + } + + callback(null); + }, + ); +}; diff --git a/Libraries/Core/setUpSystrace.js b/Libraries/Core/setUpSystrace.js new file mode 100644 index 00000000000..36a6bf40c0f --- /dev/null +++ b/Libraries/Core/setUpSystrace.js @@ -0,0 +1,20 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +/** + * Set up Systrace profiling hooks if necessary. + * You can use this module directly, or just require InitializeCore. + */ +if (global.__RCTProfileIsProfiling) { + const Systrace = require('Systrace'); + Systrace.installReactHook(); + Systrace.setEnabled(true); +} diff --git a/Libraries/Core/setUpTimers.js b/Libraries/Core/setUpTimers.js new file mode 100644 index 00000000000..1a95afa8751 --- /dev/null +++ b/Libraries/Core/setUpTimers.js @@ -0,0 +1,30 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('PolyfillFunctions'); + +/** + * Set up timers. + * You can use this module directly, or just require InitializeCore. + */ +const defineLazyTimer = name => { + polyfillGlobal(name, () => require('JSTimers')[name]); +}; +defineLazyTimer('setTimeout'); +defineLazyTimer('setInterval'); +defineLazyTimer('setImmediate'); +defineLazyTimer('clearTimeout'); +defineLazyTimer('clearInterval'); +defineLazyTimer('clearImmediate'); +defineLazyTimer('requestAnimationFrame'); +defineLazyTimer('cancelAnimationFrame'); +defineLazyTimer('requestIdleCallback'); +defineLazyTimer('cancelIdleCallback'); diff --git a/Libraries/Core/setUpXHR.js b/Libraries/Core/setUpXHR.js new file mode 100644 index 00000000000..ac528db6d7d --- /dev/null +++ b/Libraries/Core/setUpXHR.js @@ -0,0 +1,31 @@ +/** + * 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 strict-local + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('PolyfillFunctions'); + +/** + * Set up XMLHttpRequest. The native XMLHttpRequest in Chrome dev tools is CORS + * aware and won't let you fetch anything from the internet. + * + * You can use this module directly, or just require InitializeCore. + */ +polyfillGlobal('XMLHttpRequest', () => require('XMLHttpRequest')); +polyfillGlobal('FormData', () => require('FormData')); + +polyfillGlobal('fetch', () => require('fetch').fetch); // flowlint-line untyped-import:off +polyfillGlobal('Headers', () => require('fetch').Headers); // flowlint-line untyped-import:off +polyfillGlobal('Request', () => require('fetch').Request); // flowlint-line untyped-import:off +polyfillGlobal('Response', () => require('fetch').Response); // flowlint-line untyped-import:off +polyfillGlobal('WebSocket', () => require('WebSocket')); +polyfillGlobal('Blob', () => require('Blob')); +polyfillGlobal('File', () => require('File')); +polyfillGlobal('FileReader', () => require('FileReader')); +polyfillGlobal('URL', () => require('URL'));