From 9a2b9c0e43d6660055b98971d1e7466417c71708 Mon Sep 17 00:00:00 2001 From: Jhen Date: Sun, 10 Sep 2017 21:32:51 +0800 Subject: [PATCH 1/5] Ignore `__RND_INTERVAL__` logging on MessageQueue.spy --- app/worker/index.js | 2 ++ app/worker/utils.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/app/worker/index.js b/app/worker/index.js index cd8b12e2..971377e1 100644 --- a/app/worker/index.js +++ b/app/worker/index.js @@ -15,6 +15,7 @@ import { checkAvailableDevMenuMethods, invokeDevMenuMethod } from './devMenu'; import { reportDefaultReactDevToolsPort } from './reactDevTools'; import devToolsEnhancer, { composeWithDevTools } from './reduxAPI'; import * as RemoteDev from './remotedev'; +import { ignoreRNDIntervalSpy } from './utils'; /* eslint-disable no-underscore-dangle */ self.__REMOTEDEV__ = RemoteDev; @@ -39,6 +40,7 @@ const setupRNDebugger = message => { // because the changes of worker message (Redux DevTools, DevMenu) // doesn't notify to the remote JS runtime self.__RND_INTERVAL__ = setInterval(function() {}, 100); // eslint-disable-line + ignoreRNDIntervalSpy(); checkAvailableDevMenuMethods(message.networkInspect); reportDefaultReactDevToolsPort(); diff --git a/app/worker/utils.js b/app/worker/utils.js index b3c668d7..fee71872 100644 --- a/app/worker/utils.js +++ b/app/worker/utils.js @@ -1,3 +1,5 @@ +/* eslint-disable no-underscore-dangle */ + // Avoid warning of use `window.require` on dev mode export const avoidWarnForRequire = (...moduleNames) => { if (!moduleNames.length) moduleNames.push('NativeModules'); @@ -20,3 +22,34 @@ export const avoidWarnForRequire = (...moduleNames) => { }) ); }; + +const TO_JS = 0; +export const ignoreRNDIntervalSpy = async () => { + const done = await avoidWarnForRequire('MessageQueue'); + const MessageQueue = window.__DEV__ ? window.require('MessageQueue') : {}; + done(); + + MessageQueue.spy = spyOrToggle => { + if (spyOrToggle === true) { + MessageQueue.prototype.__spy = info => { + if ( + info.type === TO_JS && + info.module === 'JSTimersExecution' && + info.method === 'callTimers' && + info.args && + info.args[0] && + info.args[0][0] === self.__RND_INTERVAL__ + ) { return; } + console.log( + `${info.type === TO_JS ? 'N->JS' : 'JS->N'} : ` + + `${info.module ? `${info.module}.` : ''}${info.method}` + + `(${JSON.stringify(info.args)})` + ); + }; + } else if (spyOrToggle === false) { + MessageQueue.prototype.__spy = null; + } else { + MessageQueue.prototype.__spy = spyOrToggle; + } + }; +}; From d0be44519bd632bc6f2260dca0580eb1440ebc16 Mon Sep 17 00:00:00 2001 From: Jhen Date: Sun, 10 Sep 2017 21:53:03 +0800 Subject: [PATCH 2/5] Wrap spy function if it already set --- app/worker/utils.js | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/app/worker/utils.js b/app/worker/utils.js index fee71872..df2fd3e3 100644 --- a/app/worker/utils.js +++ b/app/worker/utils.js @@ -24,22 +24,31 @@ export const avoidWarnForRequire = (...moduleNames) => { }; const TO_JS = 0; +const isRNDInterval = info => + info.type === TO_JS && + info.module === 'JSTimersExecution' && + info.method === 'callTimers' && + info.args && + info.args[0] && + info.args[0][0] === self.__RND_INTERVAL__; + export const ignoreRNDIntervalSpy = async () => { const done = await avoidWarnForRequire('MessageQueue'); const MessageQueue = window.__DEV__ ? window.require('MessageQueue') : {}; done(); + // Wrap spy function if it already set + if (MessageQueue.prototype.__spy) { + const originalSpyFn = MessageQueue.prototype.__spy; + MessageQueue.prototype.__spy = info => { + if (isRNDInterval(info)) return; + return originalSpyFn(info); + }; + } MessageQueue.spy = spyOrToggle => { if (spyOrToggle === true) { MessageQueue.prototype.__spy = info => { - if ( - info.type === TO_JS && - info.module === 'JSTimersExecution' && - info.method === 'callTimers' && - info.args && - info.args[0] && - info.args[0][0] === self.__RND_INTERVAL__ - ) { return; } + if (isRNDInterval(info)) return; console.log( `${info.type === TO_JS ? 'N->JS' : 'JS->N'} : ` + `${info.module ? `${info.module}.` : ''}${info.method}` + @@ -49,7 +58,10 @@ export const ignoreRNDIntervalSpy = async () => { } else if (spyOrToggle === false) { MessageQueue.prototype.__spy = null; } else { - MessageQueue.prototype.__spy = spyOrToggle; + MessageQueue.prototype.__spy = info => { + if (isRNDInterval(info)) return; + return spyOrToggle(info); + }; } }; }; From ee5dd5ce32125280fcaa6441665456379d58c68e Mon Sep 17 00:00:00 2001 From: Jhen Date: Sun, 10 Sep 2017 22:02:42 +0800 Subject: [PATCH 3/5] Add MessageQueue mock to test fixture --- test/e2e/fixture/setup.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/e2e/fixture/setup.js b/test/e2e/fixture/setup.js index 25e86463..162953b5 100644 --- a/test/e2e/fixture/setup.js +++ b/test/e2e/fixture/setup.js @@ -10,6 +10,10 @@ const requiredModules = { Platform: {}, setupDevtools: undefined, AsyncStorage: {}, + MessageQueue: { + spy: () => {}, + prototype: { __spy: null }, + }, }; // Simulate React Native's window.require polyfill window.require = moduleName => { From 4ce9484ee6a51cfd0e9bce390abcb0c17c89a09c Mon Sep 17 00:00:00 2001 From: Jhen Date: Mon, 11 Sep 2017 02:18:46 +0800 Subject: [PATCH 4/5] Optimize require RN modules in worker --- app/worker/devMenu.js | 11 ++++------- app/worker/index.js | 12 ++++++------ app/worker/reactDevTools.js | 8 +------- app/worker/utils.js | 23 +++++++++++++++++------ 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/app/worker/devMenu.js b/app/worker/devMenu.js index caa5f357..6ac58186 100644 --- a/app/worker/devMenu.js +++ b/app/worker/devMenu.js @@ -1,16 +1,13 @@ /* eslint-disable no-underscore-dangle */ -import { avoidWarnForRequire } from './utils'; import { toggleNetworkInspect } from './networkInspect'; let availableDevMenuMethods = {}; -export const checkAvailableDevMenuMethods = async (enableNetworkInspect = false) => { - const done = await avoidWarnForRequire('NativeModules', 'AsyncStorage'); - const NativeModules = window.__DEV__ ? window.require('NativeModules') : {}; - const AsyncStorage = window.__DEV__ ? window.require('AsyncStorage') : {}; - done(); - +export const checkAvailableDevMenuMethods = async ( + { NativeModules, AsyncStorage }, + enableNetworkInspect = false +) => { // RN 0.43 use DevSettings, DevMenu will be deprecated const DevSettings = NativeModules.DevSettings || NativeModules.DevMenu; // Currently `show dev menu` is only on DevMenu diff --git a/app/worker/index.js b/app/worker/index.js index 971377e1..ae713ae1 100644 --- a/app/worker/index.js +++ b/app/worker/index.js @@ -15,7 +15,7 @@ import { checkAvailableDevMenuMethods, invokeDevMenuMethod } from './devMenu'; import { reportDefaultReactDevToolsPort } from './reactDevTools'; import devToolsEnhancer, { composeWithDevTools } from './reduxAPI'; import * as RemoteDev from './remotedev'; -import { ignoreRNDIntervalSpy } from './utils'; +import { getRequiredModules, ignoreRNDIntervalSpy } from './utils'; /* eslint-disable no-underscore-dangle */ self.__REMOTEDEV__ = RemoteDev; @@ -35,15 +35,15 @@ const setupRNDebuggerBeforeImportScript = message => { self.__REACT_DEVTOOLS_PORT__ = message.reactDevToolsPort; }; -const setupRNDebugger = message => { +const setupRNDebugger = async message => { // We need to regularly update JS runtime // because the changes of worker message (Redux DevTools, DevMenu) // doesn't notify to the remote JS runtime self.__RND_INTERVAL__ = setInterval(function() {}, 100); // eslint-disable-line - ignoreRNDIntervalSpy(); - - checkAvailableDevMenuMethods(message.networkInspect); - reportDefaultReactDevToolsPort(); + const modules = await getRequiredModules(); + ignoreRNDIntervalSpy(modules); + checkAvailableDevMenuMethods(modules, message.networkInspect); + reportDefaultReactDevToolsPort(modules); }; const messageHandlers = { diff --git a/app/worker/reactDevTools.js b/app/worker/reactDevTools.js index d57b680e..6ea52c64 100644 --- a/app/worker/reactDevTools.js +++ b/app/worker/reactDevTools.js @@ -1,7 +1,5 @@ /* eslint-disable no-underscore-dangle */ -import { avoidWarnForRequire } from './utils'; - const methodGlobalName = '__REPORT_REACT_DEVTOOLS_PORT__'; const reportReactDevToolsPort = (port, platform) => @@ -10,11 +8,7 @@ const reportReactDevToolsPort = (port, platform) => platform, }); -export const reportDefaultReactDevToolsPort = async () => { - const done = await avoidWarnForRequire('setupDevtools', 'Platform'); - const setupDevtools = window.__DEV__ ? window.require('setupDevtools') : undefined; - const Platform = window.__DEV__ ? window.require('Platform') : {}; - done(); +export const reportDefaultReactDevToolsPort = async ({ setupDevtools, Platform }) => { /* * [Fallback] React Native version under 0.39 can't specified the port */ diff --git a/app/worker/utils.js b/app/worker/utils.js index df2fd3e3..0f2c1b03 100644 --- a/app/worker/utils.js +++ b/app/worker/utils.js @@ -1,7 +1,7 @@ /* eslint-disable no-underscore-dangle */ // Avoid warning of use `window.require` on dev mode -export const avoidWarnForRequire = (...moduleNames) => { +const avoidWarnForRequire = moduleNames => { if (!moduleNames.length) moduleNames.push('NativeModules'); return new Promise(resolve => setTimeout(() => { @@ -23,6 +23,21 @@ export const avoidWarnForRequire = (...moduleNames) => { ); }; +const requiredModules = [ + 'MessageQueue', + 'NativeModules', + 'AsyncStorage', + 'Platform', + 'setupDevtools', +]; +export const getRequiredModules = async () => { + const done = await avoidWarnForRequire(requiredModules); + const modules = {}; + requiredModules.forEach(name => (modules[name] = window.__DEV__ ? window.require(name) : {})); + done(); + return modules; +}; + const TO_JS = 0; const isRNDInterval = info => info.type === TO_JS && @@ -32,11 +47,7 @@ const isRNDInterval = info => info.args[0] && info.args[0][0] === self.__RND_INTERVAL__; -export const ignoreRNDIntervalSpy = async () => { - const done = await avoidWarnForRequire('MessageQueue'); - const MessageQueue = window.__DEV__ ? window.require('MessageQueue') : {}; - done(); - +export const ignoreRNDIntervalSpy = async ({ MessageQueue }) => { // Wrap spy function if it already set if (MessageQueue.prototype.__spy) { const originalSpyFn = MessageQueue.prototype.__spy; From 6373c349c2797bf02fc231c5544ba412566733f7 Mon Sep 17 00:00:00 2001 From: Jhen Date: Mon, 11 Sep 2017 03:15:46 +0800 Subject: [PATCH 5/5] Avoid error if RN require polyfill is not available --- app/worker/devMenu.js | 2 +- app/worker/reactDevTools.js | 1 + app/worker/utils.js | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/worker/devMenu.js b/app/worker/devMenu.js index 6ac58186..71955ccb 100644 --- a/app/worker/devMenu.js +++ b/app/worker/devMenu.js @@ -20,7 +20,7 @@ export const checkAvailableDevMenuMethods = async ( ...DevSettings, show: showDevMenu, networkInspect: toggleNetworkInspect, - clearAsyncStorage: () => AsyncStorage.clear().catch(f => f), + clearAsyncStorage: AsyncStorage.clear ? () => AsyncStorage.clear().catch(f => f) : undefined, }; const result = Object.keys(methods).filter(key => !!methods[key]); availableDevMenuMethods = methods; diff --git a/app/worker/reactDevTools.js b/app/worker/reactDevTools.js index 6ea52c64..43bb7762 100644 --- a/app/worker/reactDevTools.js +++ b/app/worker/reactDevTools.js @@ -9,6 +9,7 @@ const reportReactDevToolsPort = (port, platform) => }); export const reportDefaultReactDevToolsPort = async ({ setupDevtools, Platform }) => { + if (Platform.__empty) return; /* * [Fallback] React Native version under 0.39 can't specified the port */ diff --git a/app/worker/utils.js b/app/worker/utils.js index 0f2c1b03..27a4a5fe 100644 --- a/app/worker/utils.js +++ b/app/worker/utils.js @@ -33,7 +33,9 @@ const requiredModules = [ export const getRequiredModules = async () => { const done = await avoidWarnForRequire(requiredModules); const modules = {}; - requiredModules.forEach(name => (modules[name] = window.__DEV__ ? window.require(name) : {})); + requiredModules.forEach( + name => (modules[name] = window.__DEV__ ? window.require(name) : { __empty: true }) + ); done(); return modules; }; @@ -48,6 +50,7 @@ const isRNDInterval = info => info.args[0][0] === self.__RND_INTERVAL__; export const ignoreRNDIntervalSpy = async ({ MessageQueue }) => { + if (MessageQueue.__empty) return; // Wrap spy function if it already set if (MessageQueue.prototype.__spy) { const originalSpyFn = MessageQueue.prototype.__spy;