Skip to content

Commit

Permalink
Added debugging docs (#3446)
Browse files Browse the repository at this point in the history
## Description

Introducing a new article to the documentation under the `Guides`
section titled `Debugging Reanimated`.
The article explains which tools can be used for debugging React Native
apps running the Reanimated module
and the limitations of each solution.

## Screenshot

<img width="782" alt="image"
src="https://user-images.githubusercontent.com/10947344/191734502-39594b86-2b49-4bb0-b994-45dd2c7dd992.png">

## Checklist

- [ ] Included code example that can be used to test this change
- [ ] Updated TS types
- [ ] Added TS types tests
- [ ] Added unit / integration tests
- [x] Updated documentation
- [x] Ensured that CI passes
  • Loading branch information
Kwasow authored Sep 22, 2022
1 parent 6985391 commit 11a919b
Show file tree
Hide file tree
Showing 22 changed files with 3,289 additions and 2,024 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/docs-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ jobs:
- name: Install node dependencies
working-directory: ${{ env.WORKING_DIRECTORY }}
run: yarn
- name: Lint check docs
working-directory: ${{ env.WORKING_DIRECTORY }}
run: yarn lint
- name: Build docs
working-directory: ${{ env.WORKING_DIRECTORY }}
run: yarn build
2 changes: 1 addition & 1 deletion docs/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
root: true,
extends: '../.eslintrc.js',
extends: ['plugin:mdx/recommended'],
};
309 changes: 309 additions & 0 deletions docs/docs/guide/debugging.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
---
id: debugging
title: "Debugging Reanimated"
sidebar_label: "Debugging Reanimated"
---

import {
SummaryTable,
ChromeDebuggerTable,
ChromeDevToolsTable,
FlipperTable,
SafariDevToolsTable,
ReactDeveloperToolsTable,
} from './debugging_tables/tables';

Due to Reanimated's unique architecture and usage of a second JS runtime, debugging
can be problematic, and some common solutions might not work as expected.
This article summarizes all the available methods and highlights their caveats.

:::info

Reanimated v1 works with all the common React Native debugging tools. This
article focuses on the use of these tools with Reanimated v2.

:::

### React Native debugging tools

These are the debugging tools we checked for compatibility with React Native
apps using the Reanimated library:

- [**Chrome debugger**](https://reactnative.dev/docs/debugging#chrome-developer-tools)
(also known as the _React Native Debugger_) is a simple tool that creates a web
worker inside your preferred browser which executes your app's JavaScript code. It works
with all the runtimes available in React Native.

- [**Chrome DevTools**](https://reactnative.dev/docs/hermes#debugging-js-on-hermes-using-google-chromes-devtools)
(unavailable for JSC) is Chrome's built-in feature that allows for connecting to a
remote JavaScript runtime. This means that the code you are debugging actually
runs on the device itself and behaves the same way as it would with DevTools detached.

- [**Flipper**](https://fbflipper.com/) (Hermes debugger) is an app created by
Facebook that makes it easy to use the _Chrome DevTools_ while providing additional tools for
UI inspection and debugging.

- [**Safari DevTools**](https://reactnative.dev/docs/debugging#safari-developer-tools)
is Safari's built-in feature that is only available for iOS devices running JSC. It works
very similarly to Chrome DevTools - it allows you to connect to a remote runtime
and keep code execution on device.

- [**React Developer Tools**](https://reactnative.dev/docs/debugging#react-developer-tools)
are a standalone app that allows debugging UI through the inspector, as well as monitoring
performance and profiling your app.

### The JS context vs. the UI context

It is important to understand the differences between the JS and UI contexts.
One thing to note is that adding Reanimated changes nothing when it comes
to debugging the regular JS context that is available in all React Native apps.
It is only debugging the UI context, which is specific to the Reanimated
library that might be difficult to debug in some scenarios, which are all
explained in this article.

You can read more about Reanimated's architecture [here](../fundamentals/architecture).

### Debugging web apps

For debugging web apps, you may use the tools you prefer or any that are provided
by the browser of your choice. We did not discover any issues with debugging
apps using Reanimated on web.

### Summary

<SummaryTable />

:::caution

Remember that console logs will always appear in the primary JS runtime as the
`console.log` function on the UI runtime is just a wrapper around the one from
the JS runtime.

:::

### Chrome Debugger

<ChromeDebuggerTable />

**Summary:**
Works, but uses web implementations of functions and runs everything on the JS thread.

Since the Chrome Debugger runs its own web worker, all the code is run on
the JS thread, and it uses the JavaScript engine provided by your web
browser (V8 in Chrome, JSC in Safari and SpiderMonkey in Firefox). This
means that this piece of code:

```js
function runWorklet() {
'worklet';
console.log('worklet:', _WORKLET);
}
runOnUI(runWorklet)();
```

would output:

```
LOG: worklet: false
```

Another side effect is that Reanimated uses web implementations of all
functions. This means that the `scrollTo` function will work
(using the native web implementation), but the `measure`
function will not be available, and its usage will trigger this error:

```
[Reanimated] measure() cannot be used for web or Chrome Debugger
```

You may still use the standard web version of `measure` as described
[here](../api/nativeMethods/measure).

Those functions that are provided by Reanimated and do not have web
implementations won't work at all.
An example of this behavior is the `useAnimatedSensor` hook,
which currently only works on mobile platforms. When debugging in Chrome and using
this hook, the following message will appear in the logs:

```
[Reanimated] useAnimatedSensor is not available on web yet.
```

But despite all of this, it is still possible to set breakpoints both in
normal JS code and in worklets (since they run on the main JS
thread now).

### Chrome DevTools

<ChromeDevToolsTable />

**Summary:**
Works and both contexts can be debugged.

:::warning

This is an early experimental feature.

:::

Worklet debugging is now available in Reanimated apps as an early experimental
feature. We do not recommend using Chrome DevTools to debug the UI context, but
instead try using the Flipper tool. It has fewer bugs and provides a much better
experience.

If you still want to use Chrome DevTools then follow these steps:

1. Add the `patch-package` to your project and set it up to run as a `post-install` task.
More details can be found [here](https://www.npmjs.com/package/patch-package).

2. Add the necessary patches to the `patches/` folder:

- [this](/content/metro-inspector-proxy+0.72.1.patch) patch for `metro-inspector-proxy`,
- [this](/content/react-native-gesture-handler+2.5.0.patch) one for `react-native-gesture-handler`
(not necessary for `react-native-gesture-handler` 2.7.0 or newer).

*Warnings about mismatched patch versions can be safely ignored if the patch was successfully applied.*

3. Open [chrome://inspect](chrome://inspect) in a Google Chrome browser.

4. Select the Reanimated runtime from the list. The list should look something
like this:

![Screenshot showing Chrome DevTools target selection](/img/debugging/ChromeDevToolsList.png)

You may choose either `Reanimated Runtime` or `Reanimated Runtime experimental
(Improved Chrome Reloads)`, but we recommend the latter.

_Debugging relies on source maps that are generated by the Reanimated Babel plugin, so you
might have to run `yarn start --reset-cache` for those changes to take effect.
In case it still doesn't work after that please reinstall the app and reset metro
cache once again._

:::caution

Known issues include:

- Reloads don't work - if a debugger is connected to the Reanimated runtime while
the reload is performed, the app will crash (both on Android and iOS)

- On iOS, a breakpoint can't be set in a line where a breakpoint was previously
set and then removed

- On iOS, breakpoint labels are not visible

- The profiler does not work (it is not possible to stop the recording) - this is an issue with Hermes and is not related
to Reanimated and has been already fixed in this [PR](https://github.com/facebook/react-native/pull/34129)

- The console is unresponsive if there are no animations running (this will be fixed in the near future)

These issues **do not** affect release builds as well as debug builds where the debugger connection
is closed while performing a reload or the debugger is not used at all.

:::

*We are actively working on improving the debugging experience with Chrome DevTools on Hermes.*

### Flipper (Hermes debugger)

<FlipperTable />

**Summary:**
Works and both contexts can be debugged.

:::warning

This is an early experimental feature.

:::

Worklet debugging is now available in Reanimated apps as an early experimental
feature. If you want to try it out follow these steps:

1. Add the `patch-package` to your project and set it up to run as a `post-install` task.
More details can be found [here](https://www.npmjs.com/package/patch-package);

2. Add the necessary patches to the `patches/` folder:

- [this](/content/metro-inspector-proxy+0.72.1.patch) patch for `metro-inspector-proxy`,
- [this](/content/react-native-gesture-handler+2.5.0.patch) one for `react-native-gesture-handler`
(not necessary for `react-native-gesture-handler` 2.7.0 or newer).

*Warnings about mismatched patch versions can be safely ignored if the patch was successfully applied.*

3. Install the `reanimated` plugin in Flipper.

![Screenshot showing where the plugin management panel is in Flipper](/img/debugging/flipper1.png)
![Screenshot showing where the install button for plugins is](/img/debugging/flipper2.png)

4. Select the plugin from the side menu (it might be disabled) and you should
be good to go!

![Screenshot showing the plugin working](/img/debugging/flipper3.png)

_Debugging relies on source maps that are generated by the Reanimated Babel plugin, so you
might have to run `yarn start --reset-cache` for those changes to take effect.
In case it still doesn't work after that please reinstall the app and reset metro
cache once again._

:::caution

Known issues include:

- Reloads don't work - if a debugger is connected to the Reanimated runtime while
the reload is performed, the app will crash (both on Android and iOS)

- Breakpoints might not be active after a reload even though they look as if they
were

- Android app crashes after the Flipper client is closed and will crash on startup
after that. This is a known Flipper issue ([link](https://github.com/facebook/flipper/issues/3026))
and is not related to Reanimated.

- The profiler does not work (it is not possible to stop the recording) - this is an issue with Hermes and is not related
to Reanimated and has been already fixed in this [PR](https://github.com/facebook/react-native/pull/34129)

- The console is unresponsive if there are no animations running (this will be fixed in the near future)

These issues **do not** affect release builds as well as debug builds where the debugger connection
is closed while performing a reload or the debugger is not used at all.

:::

*We are actively working on improving the debugging experience with Flipper on Hermes.*

### Safari DevTools

<SafariDevToolsTable />

**Summary:**
Safari DevTools is only available on iOS devices running the JSC engine.
Worklet debugging is available.

After opening Safari and configuring it as specified in the React Native
docs, under `Develop > Device` you'll see two JSC contexts
like in the screenshot below:

![Screenshot showing Safari's Develop menu options](/img/debugging/SafariJSCiOS.png)

The order of the contexts is random, but one of them will be the main JS context.
All `console.log` outputs will appear in the console of this context. You can also
set breakpoints here, but unfortunately the only source file visible is the
transformed `indexjs.bundle` which does make things more difficult to find.

The other option will be the UI context. No console logs will appear in
the console of this context, but all worklet functions should be visible
as separate files. It is also possible to set breakpoints in these
worklets.

### React Developer Tools

<ReactDeveloperToolsTable />

**Summary:**
React Developer Tools work as expected, and the profiler and layout inspector can
be used as usual.

On Android, remember to first run the command:
```
adb reverse tcp:8097 tcp:8097
```
20 changes: 20 additions & 0 deletions docs/docs/guide/debugging_tables/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.width10 {
width: 10%;
}

.width20 {
width: 20%;
}

.width30 {
width: 30%;
}

.cellNormal {
text-align: center;
}

.cellNotAvailable {
text-align: center;
color: lightgray;
}
Loading

0 comments on commit 11a919b

Please sign in to comment.