From 31cf6a7e91a56d7378790fb4b029b3c227965f1f Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Mon, 29 Jul 2019 03:15:08 -0700 Subject: [PATCH] Use Metro support for auto-collapsing internal stack frames (#25839) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/25839 Changes `ExceptionsManager` to respect the `collapse` field in each symbolicated stack frame returned from Metro, in preference to the client-side regex. This is ultimately driven by a Metro config option (now also set in the RN new project template). Note that the client-side regex is intentionally ignored for any frame where `collapse` is present ( = all of them if using the latest Metro). Also updates the client-side regex to match the new renderer paths. This is part of a redesign of work done originally in https://github.com/facebook/react-native/pull/24662; we will eventually remove the client-side regex from RN. Reviewed By: cpojer Differential Revision: D16500277 fbshipit-source-id: 557f93129d334b719200dc8603cc2345ffb45102 --- Libraries/Core/ExceptionsManager.js | 17 ++++++++++++----- Libraries/Core/NativeExceptionsManager.js | 1 + .../FBReactNativeSpec/FBReactNativeSpec.h | 6 ++++++ template/metro.config.js | 15 +++++++++++++++ 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/Libraries/Core/ExceptionsManager.js b/Libraries/Core/ExceptionsManager.js index 9d6767d51f380d..68a6214a15b7a1 100644 --- a/Libraries/Core/ExceptionsManager.js +++ b/Libraries/Core/ExceptionsManager.js @@ -12,9 +12,12 @@ import type {ExtendedError} from './Devtools/parseErrorStack'; +// NOTE: Deprecated in favor of driving this from the symbolication endpoint +// instead. +// See Metro config option `symbolicator.customizeFrame`. const INTERNAL_CALLSITES_REGEX = new RegExp( [ - '/Libraries/Renderer/oss/ReactNativeRenderer-dev\\.js$', + '/Libraries/Renderer/implementations/.+\\.js$', '/Libraries/BatchedBridge/MessageQueue\\.js$', ].join('|'), ); @@ -50,11 +53,15 @@ function reportException(e: ExtendedError, isFatal: boolean) { symbolicateStackTrace(stack) .then(prettyStack => { if (prettyStack) { - const stackWithoutInternalCallsites = prettyStack.filter( - frame => + const stackWithoutInternalCallsites = prettyStack.filter(frame => { + if (typeof frame.collapse === 'boolean') { + return !frame.collapse; + } + return ( frame.file && - frame.file.match(INTERNAL_CALLSITES_REGEX) === null, - ); + frame.file.match(INTERNAL_CALLSITES_REGEX) === null + ); + }); NativeExceptionsManager.updateExceptionMessage( message, stackWithoutInternalCallsites, diff --git a/Libraries/Core/NativeExceptionsManager.js b/Libraries/Core/NativeExceptionsManager.js index f79f2643914b1c..525d020d06960f 100644 --- a/Libraries/Core/NativeExceptionsManager.js +++ b/Libraries/Core/NativeExceptionsManager.js @@ -18,6 +18,7 @@ export type StackFrame = {| file: string, lineNumber: number, methodName: string, + collapse?: boolean, |}; export type ExceptionData = { diff --git a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h index 4630310673aeb7..21d5174c475538 100644 --- a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h +++ b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h @@ -912,6 +912,7 @@ namespace JS { NSString *file() const; double lineNumber() const; NSString *methodName() const; + folly::Optional collapse() const; StackFrame(NSDictionary *const v) : _v(v) {} private: @@ -2649,6 +2650,11 @@ inline NSString *JS::NativeExceptionsManager::StackFrame::methodName() const id const p = _v[@"methodName"]; return RCTBridgingToString(p); } +inline folly::Optional JS::NativeExceptionsManager::StackFrame::collapse() const +{ + id const p = _v[@"collapse"]; + return RCTBridgingToOptionalBool(p); +} inline NSString *JS::NativeExceptionsManager::ExceptionData::message() const { diff --git a/template/metro.config.js b/template/metro.config.js index 13a964217f20a0..ed2a70d13f89de 100644 --- a/template/metro.config.js +++ b/template/metro.config.js @@ -5,7 +5,22 @@ * @format */ +const INTERNAL_CALLSITES_REGEX = new RegExp( + [ + '/Libraries/Renderer/implementations/.+\\.js$', + '/Libraries/BatchedBridge/MessageQueue\\.js$', + ].join('|'), +); + module.exports = { + symbolicator: { + customizeFrame: frame => { + const collapse = Boolean( + frame.file && INTERNAL_CALLSITES_REGEX.test(frame.file), + ); + return {collapse}; + }, + }, transformer: { getTransformOptions: async () => ({ transform: {