Make polyfills and globals lazy

Summary:
This avoids requiring things that may never be used at all by the application such as WebSocket or Geolocation. It also stops us from asking for native modules
before we actually start the application enabling us to potentially be more lazy in the future.

Reviewed By: davidaurelio

Differential Revision: D3212802

fb-gh-sync-id: 70cf0d1a85f39fedc47758e5eb5df789a511bc9b
fbshipit-source-id: 70cf0d1a85f39fedc47758e5eb5df789a511bc9b
This commit is contained in:
Alexander Blom 2016-04-27 09:56:48 -07:00 committed by Facebook Github Bot 9
parent 9547a98a68
commit 9a3a082225
2 changed files with 90 additions and 64 deletions

View File

@ -13,6 +13,7 @@
const BatchedBridge = require('BatchedBridge');
const RemoteModules = BatchedBridge.RemoteModules;
const Platform = require('Platform');
function normalizePrefix(moduleName: string): string {
return moduleName.replace(/^(RCT|RK)/, '');
@ -65,8 +66,9 @@ Object.keys(RemoteModules).forEach((moduleName) => {
* the call sites accessing NativeModules.UIManager directly have
* been removed #9344445
*/
const UIManager = NativeModules.UIManager;
UIManager && Object.keys(UIManager).forEach(viewName => {
if (Platform.OS === 'ios') {
const UIManager = NativeModules.UIManager;
UIManager && Object.keys(UIManager).forEach(viewName => {
const viewConfig = UIManager[viewName];
if (viewConfig.Manager) {
let constants;
@ -110,6 +112,7 @@ UIManager && Object.keys(UIManager).forEach(viewName => {
},
});
}
});
});
}
module.exports = NativeModules;

View File

@ -70,6 +70,29 @@ function polyfillGlobal(name, newValue, scope = GLOBAL) {
Object.defineProperty(scope, name, {...descriptor, value: newValue});
}
function polyfillLazyGlobal(name, valueFn, scope = GLOBAL) {
if (scope[name] !== undefined) {
const descriptor = Object.getOwnPropertyDescriptor(scope, name);
const backupName = `original${name[0].toUpperCase()}${name.substr(1)}`;
Object.defineProperty(scope, backupName, {...descriptor, value: scope[name]});
}
Object.defineProperty(scope, name, {
configurable: true,
enumerable: true,
get() {
return this[name] = valueFn();
},
set(value) {
Object.defineProperty(this, name, {
configurable: true,
enumerable: true,
value
});
}
});
}
/**
* Polyfill a module if it is not already defined in `scope`.
*/
@ -104,18 +127,17 @@ function setUpErrorHandler() {
* unexplainably dropped timing signals.
*/
function setUpTimers() {
var JSTimers = require('JSTimers');
GLOBAL.setTimeout = JSTimers.setTimeout;
GLOBAL.setInterval = JSTimers.setInterval;
GLOBAL.setImmediate = JSTimers.setImmediate;
GLOBAL.clearTimeout = JSTimers.clearTimeout;
GLOBAL.clearInterval = JSTimers.clearInterval;
GLOBAL.clearImmediate = JSTimers.clearImmediate;
GLOBAL.cancelAnimationFrame = JSTimers.clearInterval;
GLOBAL.requestAnimationFrame = function(cb) {
/*requestAnimationFrame() { [native code] };*/ // Trick scroller library
return JSTimers.requestAnimationFrame(cb); // into thinking it's native
const defineLazyTimer = (name) => {
polyfillLazyGlobal(name, () => require('JSTimers')[name]);
};
defineLazyTimer('setTimeout');
defineLazyTimer('setInterval');
defineLazyTimer('setImmediate');
defineLazyTimer('clearTimeout');
defineLazyTimer('clearInterval');
defineLazyTimer('clearImmediate');
defineLazyTimer('requestAnimationFrame');
defineLazyTimer('cancelAnimationFrame');
}
function setUpAlert() {
@ -131,20 +153,19 @@ function setUpAlert() {
function setUpPromise() {
// The native Promise implementation throws the following error:
// ERROR: Event loop not supported.
GLOBAL.Promise = require('Promise');
polyfillLazyGlobal('Promise', () => require('Promise'));
}
function setUpXHR() {
// 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'));
polyfillLazyGlobal('XMLHttpRequest', () => require('XMLHttpRequest'));
polyfillLazyGlobal('FormData', () => require('FormData'));
var fetchPolyfill = require('fetch');
polyfillGlobal('fetch', fetchPolyfill.fetch);
polyfillGlobal('Headers', fetchPolyfill.Headers);
polyfillGlobal('Request', fetchPolyfill.Request);
polyfillGlobal('Response', fetchPolyfill.Response);
polyfillLazyGlobal('fetch', () => require('fetch').fetch);
polyfillLazyGlobal('Headers', () => require('fetch').Headers);
polyfillLazyGlobal('Request', () => require('fetch').Request);
polyfillLazyGlobal('Response', () => require('fetch').Response);
}
function setUpGeolocation() {
@ -153,10 +174,12 @@ function setUpGeolocation() {
enumerable: true,
configurable: true,
});
polyfillGlobal('geolocation', require('Geolocation'), GLOBAL.navigator);
polyfillLazyGlobal('geolocation', () => require('Geolocation'), GLOBAL.navigator);
}
function setUpMapAndSet() {
// We can't make these lazy as Map checks the global.Map to see if it's
// available but in our case it'll be a lazy getter.
polyfillGlobal('Map', require('Map'));
polyfillGlobal('Set', require('Set'));
}
@ -166,7 +189,7 @@ function setUpProduct() {
}
function setUpWebSockets() {
polyfillGlobal('WebSocket', require('WebSocket'));
polyfillLazyGlobal('WebSocket', () => require('WebSocket'));
}
function setUpProfile() {