Skip to content

Commit

Permalink
Modularize InitializeCore
Browse files Browse the repository at this point in the history
Summary: Split up InitializeCore into a bunch of modules. The idea here is to make it easier for apps to just get the initialization logic they want and leave behind what they don't; for example, if you don't want the Map/Set polyfills, instead of requiring InitializeCore you can require the modules you want from it.

Reviewed By: yungsters

Differential Revision: D10842564

fbshipit-source-id: 3b12d54fddea8c4ee75886022338c214987a015c
  • Loading branch information
Emily Janzer authored and facebook-github-bot committed Oct 28, 2018
1 parent 5d38264 commit df2eaa9
Show file tree
Hide file tree
Showing 15 changed files with 404 additions and 189 deletions.
203 changes: 14 additions & 189 deletions Libraries/Core/InitializeCore.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
17 changes: 17 additions & 0 deletions Libraries/Core/checkNativeVersion.js
Original file line number Diff line number Diff line change
@@ -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();
25 changes: 25 additions & 0 deletions Libraries/Core/polyfillES6Collections.js
Original file line number Diff line number Diff line change
@@ -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'));
}
21 changes: 21 additions & 0 deletions Libraries/Core/polyfillPromise.js
Original file line number Diff line number Diff line change
@@ -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'));
22 changes: 22 additions & 0 deletions Libraries/Core/setUpAlert.js
Original file line number Diff line number Diff line change
@@ -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);
};
}
42 changes: 42 additions & 0 deletions Libraries/Core/setUpBatchedBridge.js
Original file line number Diff line number Diff line change
@@ -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'));
}
28 changes: 28 additions & 0 deletions Libraries/Core/setUpDeveloperTools.js
Original file line number Diff line number Diff line change
@@ -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');

This comment has been minimized.

Copy link
@yozman

yozman Feb 25, 2019

maybe u guys should also make sure require('setupDevtools') is only use inBrowser

}

// Set up inspector
const JSInspector = require('JSInspector');
JSInspector.registerAgent(require('NetworkAgent'));
}
}
Loading

0 comments on commit df2eaa9

Please sign in to comment.