Skip to content
Open
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
7 changes: 7 additions & 0 deletions .changeset/quiet-walls-connect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'agent-react-devtools': minor
---

Automatically configure standard React Native and Expo projects through a
CommonJS Metro wrapper and a native bootstrap entry import. Unsupported Metro
formats and ambiguous projects retain the documented manual setup path.
107 changes: 100 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,21 +192,25 @@ agent-react-devtools profile diff <before.json> <after.json> [--limit N] [--thre

### Quick setup

Run the init command in your project root to auto-configure your framework:
For Vite, Next.js, and Create React App, run `init` in the project root to
patch the appropriate web entry or config:

```sh
npx agent-react-devtools init
```

This detects your framework (Vite, Next.js, CRA) and patches the appropriate config file.
For standard React Native and Expo projects, `init` also configures Metro and a
reachable app module. It supports existing CommonJS (`.js`/`.cjs`) Metro
configs and creates one when none exists. Use the manual setup below for ESM,
TypeScript, JSON/package-field, custom `--config`, or ambiguous Metro setups.

To undo these changes:

```sh
npx agent-react-devtools uninit
```

### One-line import
### Web one-line import

Add a single import as the first line of your entry point (e.g. `src/main.tsx`):

Expand Down Expand Up @@ -241,22 +245,111 @@ reactDevtools({ port: 8097, host: "localhost" });

### React Native

React Native apps connect to DevTools automatically — no code changes needed:
> Before React Native 0.87, standalone DevTools connected automatically without
> code changes. React Native 0.87 removed that path, so the setup below is now
> required.

```sh
npm install --save-dev agent-react-devtools
```

Both of the following steps are required.

`npx agent-react-devtools init` performs both steps automatically for the
common CommonJS Metro configurations and entries it recognizes: `package.json`
`main`, Expo Router's root layout, bare `index.*`, and Expo `App.*`. It patches
all available platform-specific entries when a shared entry does not exist.
The CLI first preflights every target and leaves files unchanged when it cannot
safely identify the config or entry. `uninit` removes only its marked edits.

#### 1. Wrap the final Metro config

For a bare React Native app:

```js
// metro.config.js
const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config");
const { withAgentReactDevTools } = require("agent-react-devtools/metro");

const projectConfig = {};
const config = mergeConfig(getDefaultConfig(__dirname), projectConfig);

module.exports = withAgentReactDevTools(config);
```

For Expo:

```js
// metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
const { withAgentReactDevTools } = require("agent-react-devtools/metro");

const config = getDefaultConfig(__dirname);

module.exports = withAgentReactDevTools(config);
```

Apply `withAgentReactDevTools` outermost, after all other Metro configuration
and wrappers. It preserves the final config's existing serializer hooks and
adds the agent bootstrap after React Native's own pre-main initialization.

#### 2. Import the bootstrap from the entry graph

Add this import to a user-owned module that is always reachable from the app
entry—for example, bare React Native's `index.js` or Expo Router's
`app/_layout.tsx`:

```ts
import "agent-react-devtools/react-native";
```

The import makes the bootstrap part of Metro's dependency graph. The Metro
wrapper then executes that module before application modules; its textual
position among imports does not control the execution order.

#### Run and verify

The client and daemon use port 8097 by default:

```sh
# Terminal 1
agent-react-devtools start

# Terminal 2 — restart Metro after changing metro.config.js
npx react-native start
# Expo: npx expo start

# Terminal 3
agent-react-devtools status
agent-react-devtools wait --connected --timeout 30
agent-react-devtools get tree
```

For physical devices, forward the port:
For an Android device connected over USB, forward the DevTools port before
launching the app:

```sh
adb reverse tcp:8097 tcp:8097
```

For Expo, the connection works automatically with the Expo dev client.
This integration connects only from a native development runtime. Native
production builds exit without connecting; browser and default/server imports
resolve to no-op modules.

If `status` reports zero connected apps:

1. Confirm both the Metro wrapper and graph import are present.
2. Ensure `withAgentReactDevTools` wraps the final config, outside other Metro wrappers.
3. Stop and restart Metro; if its cache is stale, use `--reset-cache` (bare) or `npx expo start -c`.
4. Confirm the daemon is listening on 8097 and repeat `adb reverse` for Android devices.
5. Check that the app is a development build.

#### Manual fallback

To use a custom port, set the `REACT_DEVTOOLS_PORT` environment variable.
Configure the two steps above manually when Metro uses ESM (`.mjs`),
TypeScript, JSON or a package-field configuration; when your app starts Metro
with a custom `--config`; or when the CLI reports an ambiguous config or entry.
Keep `withAgentReactDevTools` as the final outermost wrapper.

## Using with agent-browser

Expand Down
27 changes: 20 additions & 7 deletions examples/expo-app/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Expo Example App

A minimal React Native app using Expo to test `agent-react-devtools` integration.
A minimal Expo app showing the React Native `agent-react-devtools`
configuration.

> This fixture currently uses React Native 0.81.5, so its client-side version
> guard intentionally makes the bootstrap a no-op. It validates the Metro and
> application configuration shape, but does not validate the runtime
> connection.

## Setup

Expand All @@ -11,18 +17,29 @@ bun install

## Testing the DevTools Connection

React Native apps connect to React DevTools automatically — no code changes needed.
The example already contains both required integration points:

- [`metro.config.js`](metro.config.js) applies `withAgentReactDevTools` to the
final Expo Metro config.
- [`app/_layout.tsx`](app/_layout.tsx) imports
`agent-react-devtools/react-native` so the bootstrap is in Metro's dependency
graph.

This checked-in React Native 0.81 fixture cannot test a live connection. To
exercise the same configuration in an Expo project where the bootstrap is
active, restart Metro and run:

```sh
# Terminal 1: Start the daemon
agent-react-devtools start

# Terminal 2: Start the Expo dev server
cd examples/expo-app
bun start
bun start --clear

# Terminal 3: Inspect the app
agent-react-devtools status
agent-react-devtools wait --connected --timeout 30
agent-react-devtools get tree
```

Expand All @@ -33,7 +50,3 @@ Forward the DevTools port over USB:
```sh
adb reverse tcp:8097 tcp:8097
```

### Custom port

Set the `REACT_DEVTOOLS_PORT` environment variable before starting both the daemon and the app.
1 change: 1 addition & 0 deletions examples/expo-app/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'agent-react-devtools/react-native';
import { Stack } from 'expo-router';

export default function RootLayout() {
Expand Down
6 changes: 6 additions & 0 deletions examples/expo-app/metro.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const { getDefaultConfig } = require('expo/metro-config');
const { withAgentReactDevTools } = require('agent-react-devtools/metro');

const config = getDefaultConfig(__dirname);

module.exports = withAgentReactDevTools(config);
1 change: 1 addition & 0 deletions examples/expo-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
},
"devDependencies": {
"@types/react": "~19.1.10",
"agent-react-devtools": "workspace:*",
"typescript": "^5.5.0"
}
}
15 changes: 15 additions & 0 deletions packages/agent-react-devtools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@
"types": "./dist/connect.d.ts",
"import": "./dist/connect.js"
},
"./metro": {
"types": "./dist/metro.d.ts",
"import": "./dist/metro.js",
"require": "./dist/metro.cjs"
},
"./react-native": {
"types": "./dist/react-native.d.ts",
"browser": "./dist/react-native-noop.js",
"react-native": "./dist/react-native.js",
"default": "./dist/react-native-noop.js"
},
"./vite": {
"types": "./dist/vite.d.ts",
"import": "./dist/vite.js"
Expand Down Expand Up @@ -53,10 +64,14 @@
"zod": "^3.24.0"
},
"peerDependencies": {
"react-native": ">=0.0.0",
"react-devtools-core": ">=5.0.0",
"vite": ">=5.0.0"
},
"peerDependenciesMeta": {
"react-native": {
"optional": true
},
"react-devtools-core": {
"optional": true
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ agent-react-devtools status # Should show 1 connected app
## Important Rules

- **Labels reset** when the app reloads or components unmount/remount. After a reload, use `wait --connected` then re-check with `get tree` or `find`.
- **`status` first** — if status shows 0 connected apps, the React app is not connected. The user may need to run `npx agent-react-devtools init` in their project first.
- **`status` first** — if status shows 0 connected apps, the React app is not connected. Web users may need to run `npx agent-react-devtools init`; React Native users need both manual steps in [setup.md](references/setup.md).
- **Headed browser required** — if using `agent-browser`, always use `--headed` mode. Headless Chromium does not properly load the devtools connect script.
- **Profile while interacting** — profiling only captures renders that happen between `profile start` and `profile stop`. Make sure the relevant interaction happens during that window.
- **Use `--depth`** on large trees — a deep tree can produce a lot of output. Start with `--depth 3` or `--depth 4` and go deeper only on the subtree you care about.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ Categories with no changes are omitted. Keys are deduplicated across commits in
## Setup

### `agent-react-devtools init [--dry-run]`
Auto-detect the framework in the current directory and configure the devtools connection. Supports Vite, Next.js, CRA, and Expo/React Native.
Auto-detect the framework in the current directory. It configures Vite, Next.js,
CRA, and standard Expo/React Native projects automatically. For React Native it
patches existing CommonJS Metro configs (or creates one), then adds the native
bootstrap import to a recognized reachable app module. ESM, TypeScript, JSON or
package-field Metro configs, custom `--config` use, and ambiguous targets are
left unchanged with manual setup instructions.

Use `--dry-run` to preview changes without writing files.
Loading
Loading