House
/
Blog
/
The Current State of Debugging on React Native - Part Two: Bare RN
React Native

The Current State of Debugging on React Native - Part Two: Bare RN

As explained on part one of this post "The Current State of Debugging on React Native - Part One: EXPO", Turbo Modules changed expectations on how we can debug the running JavaScript code, disallowing the ability to debug remotely, it now requires the debug instance to connect to the JavaScript running on device.

The Current State of Debugging on React Native - Part Two: Bare RN

The purpose of this post is to explore how the experience currently is on a bare React Native setup by covering how you can: visualize logs; inspect network calls; profile and snapshot running JavaScript; and lastly step through running JavaScript code.

What's Bare React Native?

We name the default setup of React Native as bare. This setup is typically initialized by the react-native CLI program, typically by running: "npx react-native init MyFirstApp"

Output of react-native init command

Debugging On Version v0.70.6

By default on this version we have Hermes enabled and Flipper integrated. So we get the full experience of using Flipper's Hermes Debugger plugging.

One noticeable thing when coming from Expo is how encapsulates the build to avoid needing to build the app locally, with Expo you can expect to initialize a project and have it running on an emulator in less than 5 minutes, while with Bare React Native you are in charge of building locally and on iOS and Android, this can take double the time if you don't have any extra native dependencies installed and way more if you do. 

The initialized app

Stepping Through Code

There are a few ways you can trigger a breakpoint in your code. The first is using the debugger statement in code.

Debugging breakpoint

The second is calling pause yourself via Flipper's Hermes Debugger:

Pause script button

And lastly you can look up the file you are interested in and add an inline breakpoint via the debugger:

Inlined breakpoint
Gif showing how to select inline breaking via Hermes Debugger plugging

Inspecting Objects

For a short while after remote debugging via Chrome broke, all we had was Flipper and Metro's CLI output to debug logs. The shortcoming of these two tools were they didn't allow for inspection of objects the same way as Chrome did. 

Object output found in Flipper logs

You can easily see how that stringified object turns into a problem the larger it becomes.

However, with the Hermes Debugger plugin we are back to how it was:

Object output in Hermes Debugger

Network Calls

To inspect network calls Flipper has a specific plugin which we highlighted on the previous post - The current state of debugging on React Native - PART 1 EXPO. There you will also find our rant of this plugin having shortcomings in your power to inspect network waterfalls in contrast to Chrome's Network tab. With that said, nothing stops you from using 3rd party network call inspectors such as Charles.

Profiling JS

Profiling is the same as the Chrome experience with some shortcomings related to the Profiler tab.

Gif showing how to Profile JS and save the profiled file

I typically recommend to save the Profile file locally and make a few runs and analyze the resulting profile in a different place such as the Chrome Browser itself or an app like SpeedScope.

A faster and lighter weight flamegraph visualizer, SpeedScope allows you to open a profiling file

Profiling with React Dev Tools

React Dev Tools is well known and thoroughly cover in different places due to its usage on Web, let's just highlight how to use it here as well for the purpose of completeness:

A gif of recording a session with React Dev tools

The strategy with either way of profiling should always be:

  1. Isolate the problem
  2. Run the offending or case up for analysis
  3. Save the profile
  4. Run again at least 4 times
  5. Analyze flamegraph looking for recurring themes between saved profiling files

Memory Snapshots

Memory snapshots are typically done by doing two snapshots for comparison. This allows you to spot where new memory allocations are and how where a memory leak could be:

Gif of doing memory snapshots with Hermes Debugger plugin

Final Thoughts

This time we won't cover Android since with Hermes enabled the experience is the same. Both React Native and Expo have similar experiences when using Hermes with the exception that before Expo 47 (not yet published at the time of this writing) you would need to do some lift to integrate Flipper into Expo. 

Further, the entire idea of debugging JavaScript directly on device - see discussion for context, is still very new and typically unsupported by other JS engines. Right now JSC has a low bar experience with debugging with Safari on iOS and V8 does a better job with chrome://inspect on Android as noted on the previous post.

We will cover how to properly debug JSC via Safari for iOS on a separate post which will also contain a fix to get inlined source files working. 

Lastly the experience with V8 engine was covered already in The Current State of Debugging on React Native - Part One: EXPO.

We believe the debugging experience is still not as good as it could be and the React Native Core team has acknowledged and expressed absolute interest in driving improvements to Hermes' Chrome Debugger protocol to allow us to use Chrome Dev Tools again as default. 

React Native

The Current State of Debugging on React Native - Part Two: Bare RN

/
The Current State of Debugging on React Native - Part Two: Bare RN
As explained on part one of this post "The Current State of Debugging on React Native - Part One: EXPO", Turbo Modules changed expectations on how we can debug the running JavaScript code, disallowing the ability to debug remotely, it now requires the debug instance to connect to the JavaScript running on device.

The purpose of this post is to explore how the experience currently is on a bare React Native setup by covering how you can: visualize logs; inspect network calls; profile and snapshot running JavaScript; and lastly step through running JavaScript code.

What's Bare React Native?

We name the default setup of React Native as bare. This setup is typically initialized by the react-native CLI program, typically by running: "npx react-native init MyFirstApp"

Output of react-native init command

Debugging On Version v0.70.6

By default on this version we have Hermes enabled and Flipper integrated. So we get the full experience of using Flipper's Hermes Debugger plugging.

One noticeable thing when coming from Expo is how encapsulates the build to avoid needing to build the app locally, with Expo you can expect to initialize a project and have it running on an emulator in less than 5 minutes, while with Bare React Native you are in charge of building locally and on iOS and Android, this can take double the time if you don't have any extra native dependencies installed and way more if you do. 

The initialized app

Stepping Through Code

There are a few ways you can trigger a breakpoint in your code. The first is using the debugger statement in code.

Debugging breakpoint

The second is calling pause yourself via Flipper's Hermes Debugger:

Pause script button

And lastly you can look up the file you are interested in and add an inline breakpoint via the debugger:

Inlined breakpoint
Gif showing how to select inline breaking via Hermes Debugger plugging

Inspecting Objects

For a short while after remote debugging via Chrome broke, all we had was Flipper and Metro's CLI output to debug logs. The shortcoming of these two tools were they didn't allow for inspection of objects the same way as Chrome did. 

Object output found in Flipper logs

You can easily see how that stringified object turns into a problem the larger it becomes.

However, with the Hermes Debugger plugin we are back to how it was:

Object output in Hermes Debugger

Network Calls

To inspect network calls Flipper has a specific plugin which we highlighted on the previous post - The current state of debugging on React Native - PART 1 EXPO. There you will also find our rant of this plugin having shortcomings in your power to inspect network waterfalls in contrast to Chrome's Network tab. With that said, nothing stops you from using 3rd party network call inspectors such as Charles.

Profiling JS

Profiling is the same as the Chrome experience with some shortcomings related to the Profiler tab.

Gif showing how to Profile JS and save the profiled file

I typically recommend to save the Profile file locally and make a few runs and analyze the resulting profile in a different place such as the Chrome Browser itself or an app like SpeedScope.

A faster and lighter weight flamegraph visualizer, SpeedScope allows you to open a profiling file

Profiling with React Dev Tools

React Dev Tools is well known and thoroughly cover in different places due to its usage on Web, let's just highlight how to use it here as well for the purpose of completeness:

A gif of recording a session with React Dev tools

The strategy with either way of profiling should always be:

  1. Isolate the problem
  2. Run the offending or case up for analysis
  3. Save the profile
  4. Run again at least 4 times
  5. Analyze flamegraph looking for recurring themes between saved profiling files

Memory Snapshots

Memory snapshots are typically done by doing two snapshots for comparison. This allows you to spot where new memory allocations are and how where a memory leak could be:

Gif of doing memory snapshots with Hermes Debugger plugin

Final Thoughts

This time we won't cover Android since with Hermes enabled the experience is the same. Both React Native and Expo have similar experiences when using Hermes with the exception that before Expo 47 (not yet published at the time of this writing) you would need to do some lift to integrate Flipper into Expo. 

Further, the entire idea of debugging JavaScript directly on device - see discussion for context, is still very new and typically unsupported by other JS engines. Right now JSC has a low bar experience with debugging with Safari on iOS and V8 does a better job with chrome://inspect on Android as noted on the previous post.

We will cover how to properly debug JSC via Safari for iOS on a separate post which will also contain a fix to get inlined source files working. 

Lastly the experience with V8 engine was covered already in The Current State of Debugging on React Native - Part One: EXPO.

We believe the debugging experience is still not as good as it could be and the React Native Core team has acknowledged and expressed absolute interest in driving improvements to Hermes' Chrome Debugger protocol to allow us to use Chrome Dev Tools again as default. 

About the Author
React

Hire vetted remote developers today

Technology leaders rely on G2i to hire freelance software developers, find full-time engineers, and build entire teams.

Group

More from G2i