From f9b744d50137de25357994fe2e829f98104e2242 Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Mon, 7 Dec 2015 16:54:18 -0800 Subject: [PATCH] Use lazy getters to reduce `require('react-native')` overhead Summary: public In the open source React Native implementation, the recommended approach for importing modules is by importing a the `ReactNative` object, which includes all available modules. This is rather inefficient because it ends up initializing all the JS modules, even if you don't use them. This diff switches the properties of the `ReactNative ` object to lazy getter functions, which defers the `require` until the module is actually requested. This doesn't prevent unused modules from being included in the JS bundle, but it will prevent them from being initialized unless/until they are used. Reviewed By: vjeux Differential Revision: D2722993 fb-gh-sync-id: 0e9a2beb3aa6cd087a0592bd59a8f9242040be0c --- Libraries/react-native/react-native.js | 174 +++++++++++++------------ 1 file changed, 89 insertions(+), 85 deletions(-) diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js index 99bda63a9..9eb675a84 100644 --- a/Libraries/react-native/react-native.js +++ b/Libraries/react-native/react-native.js @@ -6,110 +6,114 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * @noflow - get/set properties not yet supported by flow. also `...require(x)` is broken #6560135 */ 'use strict'; // Export React, plus some native additions. -// -// The use of Object.create/assign is to work around a Flow bug (#6560135). -// Once that is fixed, change this back to -// -// var ReactNative = {...require('React'), /* additions */} -// -var ReactNative = Object.assign(Object.create(require('React')), { +var ReactNative = { // Components - ActivityIndicatorIOS: require('ActivityIndicatorIOS'), - ART: require('ReactNativeART'), - DatePickerIOS: require('DatePickerIOS'), - DrawerLayoutAndroid: require('DrawerLayoutAndroid'), - Image: require('Image'), - ListView: require('ListView'), - MapView: require('MapView'), - Modal: require('Modal'), - Navigator: require('Navigator'), - NavigatorIOS: require('NavigatorIOS'), - PickerIOS: require('PickerIOS'), - ProgressBarAndroid: require('ProgressBarAndroid'), - ProgressViewIOS: require('ProgressViewIOS'), - ScrollView: require('ScrollView'), - SegmentedControlIOS: require('SegmentedControlIOS'), - SliderIOS: require('SliderIOS'), - SnapshotViewIOS: require('SnapshotViewIOS'), - Switch: require('Switch'), - PullToRefreshViewAndroid: require('PullToRefreshViewAndroid'), - SwitchAndroid: require('SwitchAndroid'), - SwitchIOS: require('SwitchIOS'), - TabBarIOS: require('TabBarIOS'), - Text: require('Text'), - TextInput: require('TextInput'), - ToastAndroid: require('ToastAndroid'), - ToolbarAndroid: require('ToolbarAndroid'), - Touchable: require('Touchable'), - TouchableHighlight: require('TouchableHighlight'), - TouchableNativeFeedback: require('TouchableNativeFeedback'), - TouchableOpacity: require('TouchableOpacity'), - TouchableWithoutFeedback: require('TouchableWithoutFeedback'), - View: require('View'), - ViewPagerAndroid: require('ViewPagerAndroid'), - WebView: require('WebView'), + get ActivityIndicatorIOS() { return require('ActivityIndicatorIOS'); }, + get ART() { return require('ReactNativeART'); }, + get DatePickerIOS() { return require('DatePickerIOS'); }, + get DrawerLayoutAndroid() { return require('DrawerLayoutAndroid'); }, + get Image() { return require('Image'); }, + get ListView() { return require('ListView'); }, + get MapView() { return require('MapView'); }, + get Modal() { return require('Modal'); }, + get Navigator() { return require('Navigator'); }, + get NavigatorIOS() { return require('NavigatorIOS'); }, + get PickerIOS() { return require('PickerIOS'); }, + get ProgressBarAndroid() { return require('ProgressBarAndroid'); }, + get ProgressViewIOS() { return require('ProgressViewIOS'); }, + get ScrollView() { return require('ScrollView'); }, + get SegmentedControlIOS() { return require('SegmentedControlIOS'); }, + get SliderIOS() { return require('SliderIOS'); }, + get SnapshotViewIOS() { return require('SnapshotViewIOS'); }, + get Switch() { return require('Switch'); }, + get PullToRefreshViewAndroid() { return require('PullToRefreshViewAndroid'); }, + get SwitchAndroid() { return require('SwitchAndroid'); }, + get SwitchIOS() { return require('SwitchIOS'); }, + get TabBarIOS() { return require('TabBarIOS'); }, + get Text() { return require('Text'); }, + get TextInput() { return require('TextInput'); }, + get ToastAndroid() { return require('ToastAndroid'); }, + get ToolbarAndroid() { return require('ToolbarAndroid'); }, + get Touchable() { return require('Touchable'); }, + get TouchableHighlight() { return require('TouchableHighlight'); }, + get TouchableNativeFeedback() { return require('TouchableNativeFeedback'); }, + get TouchableOpacity() { return require('TouchableOpacity'); }, + get TouchableWithoutFeedback() { return require('TouchableWithoutFeedback'); }, + get View() { return require('View'); }, + get ViewPagerAndroid() { return require('ViewPagerAndroid'); }, + get WebView() { return require('WebView'); }, // APIs - ActionSheetIOS: require('ActionSheetIOS'), - AdSupportIOS: require('AdSupportIOS'), - AlertIOS: require('AlertIOS'), - Animated: require('Animated'), - AppRegistry: require('AppRegistry'), - AppStateIOS: require('AppStateIOS'), - AsyncStorage: require('AsyncStorage'), - BackAndroid: require('BackAndroid'), - CameraRoll: require('CameraRoll'), - Dimensions: require('Dimensions'), - Easing: require('Easing'), - ImagePickerIOS: require('ImagePickerIOS'), - IntentAndroid: require('IntentAndroid'), - InteractionManager: require('InteractionManager'), - LayoutAnimation: require('LayoutAnimation'), - LinkingIOS: require('LinkingIOS'), - NetInfo: require('NetInfo'), - PanResponder: require('PanResponder'), - PixelRatio: require('PixelRatio'), - PushNotificationIOS: require('PushNotificationIOS'), - Settings: require('Settings'), - StatusBarIOS: require('StatusBarIOS'), - StyleSheet: require('StyleSheet'), - UIManager: require('UIManager'), - VibrationIOS: require('VibrationIOS'), + get ActionSheetIOS() { return require('ActionSheetIOS'); }, + get AdSupportIOS() { return require('AdSupportIOS'); }, + get AlertIOS() { return require('AlertIOS'); }, + get Animated() { return require('Animated'); }, + get AppRegistry() { return require('AppRegistry'); }, + get AppStateIOS() { return require('AppStateIOS'); }, + get AsyncStorage() { return require('AsyncStorage'); }, + get BackAndroid() { return require('BackAndroid'); }, + get CameraRoll() { return require('CameraRoll'); }, + get Dimensions() { return require('Dimensions'); }, + get Easing() { return require('Easing'); }, + get ImagePickerIOS() { return require('ImagePickerIOS'); }, + get IntentAndroid() { return require('IntentAndroid'); }, + get InteractionManager() { return require('InteractionManager'); }, + get LayoutAnimation() { return require('LayoutAnimation'); }, + get LinkingIOS() { return require('LinkingIOS'); }, + get NetInfo() { return require('NetInfo'); }, + get PanResponder() { return require('PanResponder'); }, + get PixelRatio() { return require('PixelRatio'); }, + get PushNotificationIOS() { return require('PushNotificationIOS'); }, + get Settings() { return require('Settings'); }, + get StatusBarIOS() { return require('StatusBarIOS'); }, + get StyleSheet() { return require('StyleSheet'); }, + get UIManager() { return require('UIManager'); }, + get VibrationIOS() { return require('VibrationIOS'); }, // Plugins - DeviceEventEmitter: require('RCTDeviceEventEmitter'), - NativeAppEventEmitter: require('RCTNativeAppEventEmitter'), - NativeModules: require('NativeModules'), - Platform: require('Platform'), - processColor: require('processColor'), - requireNativeComponent: require('requireNativeComponent'), + get DeviceEventEmitter() { return require('RCTDeviceEventEmitter'); }, + get NativeAppEventEmitter() { return require('RCTNativeAppEventEmitter'); }, + get NativeModules() { return require('NativeModules'); }, + get Platform() { return require('Platform'); }, + get processColor() { return require('processColor'); }, + get requireNativeComponent() { return require('requireNativeComponent'); }, // Prop Types - EdgeInsetsPropType: require('EdgeInsetsPropType'), - PointPropType: require('PointPropType'), + get EdgeInsetsPropType() { return require('EdgeInsetsPropType'); }, + get PointPropType() { return require('PointPropType'); }, // See http://facebook.github.io/react/docs/addons.html addons: { - LinkedStateMixin: require('LinkedStateMixin'), + get LinkedStateMixin() { return require('LinkedStateMixin'); }, Perf: undefined, - PureRenderMixin: require('ReactComponentWithPureRenderMixin'), - TestModule: require('NativeModules').TestModule, + get PureRenderMixin() { return require('ReactComponentWithPureRenderMixin'); }, + get TestModule() { return require('NativeModules').TestModule; }, TestUtils: undefined, - batchedUpdates: require('ReactUpdates').batchedUpdates, - cloneWithProps: require('cloneWithProps'), - createFragment: require('ReactFragment').create, - update: require('update'), + get batchedUpdates() { return require('ReactUpdates').batchedUpdates; }, + get cloneWithProps() { return require('cloneWithProps'); }, + get createFragment() { return require('ReactFragment').create; }, + get update() { return require('update'); }, }, -}); + + // Note: this must be placed last to prevent eager + // evaluation of the getter-wrapped submodules above + ...require('React'), +}; if (__DEV__) { - ReactNative.addons.Perf = require('ReactDefaultPerf'); - ReactNative.addons.TestUtils = require('ReactTestUtils'); + Object.defineProperty(ReactNative.addons, 'Perf', { + enumerable: true, + get: () => require('ReactDefaultPerf'), + }); + Object.defineProperty(ReactNative.addons, 'TestUtils', { + enumerable: true, + get: () => require('ReactTestUtils'), + }); } module.exports = ReactNative;