Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 119 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,44 @@
![release-inspector-banner](./docs/assets/banner.png)

[![mit licence][license-badge]][license]
[![npm downloads][npm-downloads-badge]][npm-downloads]
[![PRs Welcome][prs-welcome-badge]][prs-welcome]

# react-native-release-inspector

Profile React Native App in Release mode with React DevTools for React.Profiler
The React on Web allows the users to run [profilable](https://react.dev/reference/dev-tools/react-performance-tracks#using-profiling-builds) builds to get near to production experience. This is the sweetest spot to having more confident profiling. However, on React Native this wasn't possible until now.

This package fixes this gap following the same analogy from React on Web, by allowing React Native to load Profiling shim for Release builds. 🚀

## Demo

![release-inspector](./docs/assets/inspector.gif)

<hr/>

## Applications

**Why you need this?**

#### Profiling React Components in Release builds

Most teams leverage React DevTools to profile their components in Debug Builds. If you are looking to profile React Components in Release builds, then this package is for you.

![Release Profilng](./docs/assets/release.png)

#### Inspecting React.Profiler callbacks in Release builds

Teams can have a use case where they leverage `React.Profiler` and perform their calculations from the values of the `onRender` callback. In debug builds, this works very well. If you are also interested in running these calculations in release builds, then this package is for you.

```ts
function onRender(id, phase, actualDuration, baseDuration, startTime, commitTime) {
// Aggregate or log render timings...
}

<Profiler id="App" onRender={onRender}>
<App />
</Profiler>
```

## Installation

Expand All @@ -10,29 +48,100 @@ npm install @callstack/react-native-release-inspector

## Usage

```js
import { multiply } from '@callstack/react-native-release-inspector';
#### Step 1:
Add this to the top level of `index.js`:

// ...
```diff
+import '@callstack/react-native-release-inspector';
import { AppRegistry } from 'react-native';
```

const result = multiply(3, 7);
#### Step 2:
Update your `metro.config` with `withReactNativeReleaseInspector`:

```diff
+const {
+ withReactNativeReleaseInspector,
+} = require('@callstack/react-native-release-inspector/metro');

const root = path.resolve(__dirname, '../..');

const config = withMetroConfig(getDefaultConfig(__dirname), {
root,
dirname: __dirname,
});

+module.exports = withReactNativeReleaseInspector(config, true);
```

## Repository structure
#### Step 3:
Start the inspector in a terminal:

- Library package: `packages/react-native-release-inspector`
- Example app: `apps/example`
```bash
npx inspector start
```

<br/>
Now build and run your app in release mode, you should see the react devtools connected to your Application. 🚀

<hr/>

## Configurations

### API

The `@callstack/react-native-release-inspector` requires the user to configure their `metro.config` as shown above. This `withReactNativeReleaseInspector` receives the following arguments:

- `withReactNativeReleaseInspector(config, enabled)`
- `config: MetroConfig`
- User only need to pass the config instance from Metro
- `enabled: Boolean`
- Default value is false.
- If true, enables profiling to work in release builds.

### CLI

The `@callstack/react-native-release-inspector` exposes a CLI `inspector` to start the instance of React DevTools.

It supports the following options:

| Option | Purpose |
| --------------- | ------ |
| start | kicks off the instance of React DevTools |
| help or -h | prints how to use the CLI |

Sample Usages:

```bash
yarn inspector start
yarn inspector help
yarn inspector -h
```
<hr/>

## Contributing

- [Development workflow](CONTRIBUTING.md#development-workflow)
- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)
- [Code of conduct](CODE_OF_CONDUCT.md)

## License
## Made with ❤️ at Callstack

MIT
**react-native-release-inspector** is an open source project and will always remain free to use. If you think it's cool, please star it 🌟.

[Callstack](https://www.callstack.com/) is a group of React and React Native geeks, contact us at [hello@callstack.com](mailto:hello@callstack.com) if you need any help with these or just want to say hi!

---

Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)

## License

MIT

[license-badge]: https://img.shields.io/npm/l/react-native-release-inspector?style=for-the-badge
[license]: https://github.com/callstackincubator/react-native-release-inspector/blob/main/LICENSE
[npm-downloads-badge]: https://img.shields.io/npm/dm/react-native-release-inspector?style=for-the-badge
[npm-downloads]: https://www.npmjs.com/package/react-native-release-inspector
[prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge
[prs-welcome]: https://github.com/callstackincubator/react-native-release-inspector
124 changes: 124 additions & 0 deletions apps/example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,75 @@ PODS:
- React-RCTFBReactNativeSpec
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- react-native-safe-area-context (5.8.0):
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- react-native-safe-area-context/common (= 5.8.0)
- react-native-safe-area-context/fabric (= 5.8.0)
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- react-native-safe-area-context/common (5.8.0):
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- react-native-safe-area-context/fabric (5.8.0):
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- react-native-safe-area-context/common
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- React-NativeModulesApple (0.85.0):
- hermes-engine
- React-callinvoker
Expand Down Expand Up @@ -1747,6 +1816,53 @@ PODS:
- React-utils (= 0.85.0)
- ReactNativeDependencies
- ReactNativeDependencies (0.85.0)
- RNScreens (4.25.1):
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-RCTImage
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- RNScreens/common (= 4.25.1)
- Yoga
- RNScreens/common (4.25.1):
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-RCTImage
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- Yoga (0.0.0)

DEPENDENCIES:
Expand Down Expand Up @@ -1789,6 +1905,7 @@ DEPENDENCIES:
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
- React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-networking (from `../node_modules/react-native/ReactCommon/react/networking`)
- React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`)
Expand Down Expand Up @@ -1823,6 +1940,7 @@ DEPENDENCIES:
- ReactCodegen (from `build/generated/ios/ReactCodegen`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`)
- RNScreens (from `../node_modules/react-native-screens`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)

EXTERNAL SOURCES:
Expand Down Expand Up @@ -1903,6 +2021,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon"
React-microtasksnativemodule:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
React-NativeModulesApple:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios"
React-networking:
Expand Down Expand Up @@ -1971,6 +2091,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon"
ReactNativeDependencies:
:podspec: "../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec"
RNScreens:
:path: "../node_modules/react-native-screens"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"

Expand Down Expand Up @@ -2013,6 +2135,7 @@ SPEC CHECKSUMS:
React-logger: ee47d5f3b59a46a006c65038ed5d0b1143e37510
React-Mapbuffer: 7f8bfbe3fcb2203db4ccb3975414af8cabe4bcd0
React-microtasksnativemodule: ca1f33f7c98b76d923f550d39631eb4e05fa9aec
react-native-safe-area-context: fb5c8ee9f6dd62ef710611b3d370c501f42a4ac0
React-NativeModulesApple: 9c1f8815ebd72cc1c75587fe588513f6dd9cb708
React-networking: 8f75f882c6794e91e28b458b5bc1461034098c80
React-oscompat: 5361d0fa7905ba1c3b3c5e7c464d6be9d2d85f4b
Expand Down Expand Up @@ -2047,6 +2170,7 @@ SPEC CHECKSUMS:
ReactCodegen: b3184a229afd01e7f8058dd81b805b843caa2bf9
ReactCommon: fe2a3af8975e63efa60f95fca8c34dc85deee360
ReactNativeDependencies: e791424e30706256b549eaf97aaca169ca170c2b
RNScreens: 75d04ea58bd7a8e8ac60b7968d0382aa71631a7d
Yoga: e83c3121d079541e69f3c5c623faaaf933fb5812

PODFILE CHECKSUM: 4a21655142e46a595eeb8a1e91de752c15ab3838
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Release"
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
Expand Down
6 changes: 5 additions & 1 deletion apps/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@
},
"dependencies": {
"@callstack/react-native-release-inspector": "workspace:*",
"@react-navigation/native": "^7.2.4",
"@react-navigation/native-stack": "^7.15.1",
"react": "19.2.3",
"react-native": "0.85.0"
"react-native": "0.85.0",
"react-native-safe-area-context": "^5.8.0",
"react-native-screens": "^4.25.1"
},
"devDependencies": {
"@babel/core": "^7.25.2",
Expand Down
18 changes: 3 additions & 15 deletions apps/example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
import { Text, View, StyleSheet } from 'react-native';
import { Navigation } from './navigation';

export default function App() {
return (
<View style={styles.container}>
<Text>Result: 3</Text>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
return <Navigation />;
}
Loading
Loading