From ae5de54f009c2c57cb7d69d8770a92871e8d266e Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 22 Oct 2015 05:51:21 -0700
Subject: [PATCH] Reduced module config data

Summary: public

We're sending a lot of module config data when the app first starts, and much of this is redundant.

UIExplorer current sends 19061 bytes of module config JSON. This diff reduces that to 16104 (15% saving) by stripping modules that have no methods or constants, and removing method types unless method is async.

Reviewed By: tadeuzagallo, javache

Differential Revision: D2570010

fb-gh-sync-id: 8c0abbd1cdee3264b37a4f52e852008caaffb9c5
---
 Libraries/Utilities/MessageQueue.js | 14 +++++++++-----
 React/Base/RCTBatchedBridge.m       |  5 ++++-
 React/Base/RCTModuleData.m          | 22 +++++++++++++++++-----
 3 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index d34bda8b9..d37881d91 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -186,7 +186,7 @@ class MessageQueue {
     let moduleNames = Object.keys(localModules);
     for (var i = 0, l = moduleNames.length; i < l; i++) {
       let moduleName = moduleNames[i];
-      let methods = localModules[moduleName].methods;
+      let methods = localModules[moduleName].methods || {};
       let moduleID = localModules[moduleName].moduleID;
       moduleTable[moduleID] = moduleName;
       methodTable[moduleID] = {};
@@ -210,12 +210,16 @@ class MessageQueue {
   }
 
   _genModule(module, moduleConfig) {
-    let methodNames = Object.keys(moduleConfig.methods);
+    let methods = moduleConfig.methods || {};
+    let methodNames = Object.keys(methods);
     for (var i = 0, l = methodNames.length; i < l; i++) {
       let methodName = methodNames[i];
-      let methodConfig = moduleConfig.methods[methodName];
+      let methodConfig = methods[methodName];
       module[methodName] = this._genMethod(
-        moduleConfig.moduleID, methodConfig.methodID, methodConfig.type);
+        moduleConfig.moduleID,
+        methodConfig.methodID,
+        methodConfig.type || MethodTypes.remote
+      );
     }
     Object.assign(module, moduleConfig.constants);
     return module;
@@ -260,7 +264,7 @@ class MessageQueue {
 
 }
 
-function createErrorFromErrorData(errorData: ErrorData): Error {
+function createErrorFromErrorData(errorData: {message: string}): Error {
   var {
     message,
     ...extraErrorInfo,
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index aedb23008..3906a5bdc 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -310,7 +310,10 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void);
 {
   NSMutableDictionary *config = [NSMutableDictionary new];
   for (RCTModuleData *moduleData in _moduleDataByID) {
-    config[moduleData.name] = moduleData.config;
+    NSDictionary *moduleConfig = moduleData.config;
+    if (moduleConfig) {
+      config[moduleData.name] = moduleConfig;
+    }
     if ([moduleData.instance conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
       [_frameUpdateObservers addObject:moduleData];
 
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index 23f46cb79..a95d79dd6 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -81,6 +81,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
 
 - (NSDictionary *)config
 {
+  if (_constants.count == 0 && self.methods.count == 0) {
+    return nil; // Nothing to export
+  }
+
   NSMutableDictionary *config = [NSMutableDictionary new];
   config[@"moduleID"] = _moduleID;
 
@@ -90,12 +94,20 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
 
   NSMutableDictionary *methodconfig = [NSMutableDictionary new];
   [self.methods enumerateObjectsUsingBlock:^(id<RCTBridgeMethod> method, NSUInteger idx, __unused BOOL *stop) {
-    methodconfig[method.JSMethodName] = @{
-      @"methodID": @(idx),
-      @"type": method.functionType == RCTFunctionTypePromise ? @"remoteAsync" : @"remote",
-    };
+    if (method.functionType == RCTFunctionTypePromise) {
+      methodconfig[method.JSMethodName] = @{
+        @"methodID": @(idx),
+        @"type": @"remoteAsync",
+      };
+    } else {
+      methodconfig[method.JSMethodName] = @{
+        @"methodID": @(idx),
+      };
+    }
   }];
-  config[@"methods"] = [methodconfig copy];
+  if (methodconfig.count) {
+    config[@"methods"] = [methodconfig copy];
+  }
 
   return [config copy];
 }