Skip to content

open-source-labs/Reactime-Native

Reactime Native (Alpha)

A React Native time-travel debugger inspired by Reactime. Unlike the original Chrome extension, this project targets React Native apps (Expo, Metro, Hermes) and runs with no native code β€” only JavaScript.

This project is currently in alpha. The team is actively building out important features and plan to package for npm soon.


Status

Alpha stage. Not production-ready. The team is building toward an npm package release.

Currently you can:

  • Stream React Native state snapshots over WebSocket
  • Scrub through state history in a browser-based debugger
  • Capture early performance metrics (commit duration, lag)
  • Manage snapshot history with Redux Toolkit on the frontend

Architecture

graph LR
    A[React Native App] -->|Redux middleware| B[WS Client]
    B -->|ws://host:8080| C[Node.js Server<br/>port 8080]
    C -->|broadcast| D[Browser Debugger<br/>localhost:5173]
    D -->|Redux slice| E[Timeline UI]
Loading

Reactime Native is split into three moving parts:

  1. Agent (inside RN app)

    • Hooks into the React DevTools global hook (__REACT_DEVTOOLS_GLOBAL_HOOK__)
    • Intercepts Fiber commits
    • Traverses the Fiber tree to collect props/state
    • Serializes snapshots and streams them over WebSocket
  2. WebSocket server

    • Simple Node server that relays snapshots from RN β†’ browser UI
    • Acts as the "bridge" layer between environments
  3. Debugger UI (browser)

    • Built with React + Vite
    • Uses Redux Toolkit slices to store snapshots, metrics, and UI state
    • Provides timeline scrubber, import/export, and basic controls

Snapshot capture + replay flow

sequenceDiagram
    participant RN as React Native App
    participant S  as WS Server
    participant UI as Browser Debugger

    RN->>S: {channel:'snapshot', type:'add', payload}
    S->>UI: broadcast snapshot
    UI->>UI: dispatch addSnapshot β†’ Redux store
    UI->>UI: TimelineSlider updates

    Note over UI: Developer scrubs timeline

    Note over UI,RN: 🚧 Planned (v0.2.0) β€” bidirectional replay not yet implemented
    UI-->>S: {channel:'snapshot', type:'jumpTo', payload:{index}}
    S-->>RN: forward jumpTo command
Loading

Key Features

  • WebSocket relay β€” real-time, bidirectional bridge between the RN app and browser debugger using the native WebSocket API (no Socket.IO)
  • Redux Toolkit β€” centralized snapshot history, timeline index, and performance metrics shared across all browser UI components via feature slices
  • TypeScript strict mode β€” end-to-end typed: RN middleware, WebSocket server contracts, Redux slices, and all browser UI components
  • Snapshot diff view β€” color-coded line-level diff between consecutive snapshots (added / removed / changed / unchanged) with recursive nested object support
  • Component tree β€” collapsible component hierarchy rendered from snapshot data; nodes with state changes highlighted with a visual badge
  • Keyboard accessibility (WCAG 2.1.1) β€” timeline scrubber supports arrow key navigation; component tree supports ArrowRight/Left/Enter/Space; all interactive controls have visible focus rings
  • Vitest test suite β€” unit and integration tests across all three packages with environment-specific configs (jsdom for browser client, node for RN + server)
  • Dynamic IP resolution β€” wsConfig.ts fallback chain (EXPO_PUBLIC_WS_HOST β†’ Expo hostUri β†’ Android emulator β†’ localhost) eliminates hardcoded IPs across dev environments

Fiber: What We're Capturing

React uses an internal Fiber tree to track every component instance.

  • Think of it as React's equivalent of the DOM tree: each node holds props, state, hooks, and children.
  • On every commit, React walks this tree to decide what to update on screen.

In our agent code (MobileSample.tsx), we:

  • Subscribe to onCommitFiberRoot
  • Traverse the Fiber tree for only the stateful components
  • Convert each new commit as a "snapshot" and feed in a serialized JSON representation
  • Broadcast snapshots to the WebSocket server

The frontend debugger UI then reconstructs these snapshots into a timeline view.


Architecture Decisions

Decision Choice Rationale
Transport Native WebSocket API No Socket.IO overhead; reliable RN compatibility
MVP scope One-way flow (RN β†’ browser) Delivers core observability value without blocking on bidirectional complexity
IP resolution wsConfig.ts fallback chain Eliminates hardcoded IPs; any dev sets EXPO_PUBLIC_WS_HOST in .env.local
Server design createServer() factory + require.main guard Separates library behavior from CLI; makes broadcast() unit-testable
Browser state Redux Toolkit slices Shared snapshot history + metrics across multiple components without prop drilling

See CLAUDE.md for the full engineering decision log.


Environment Variables

Variable Where Description
EXPO_PUBLIC_WS_HOST sample-RN-app/.env.local Override WebSocket host (LAN IP or hostname). Strips any leading scheme or embedded port automatically.

The browser client connects to ws://localhost:8080 by default. Update client/src/transport/socket.ts if your server runs on a different host.


Running Tests

Each package has its own Vitest config with environment-specific settings (jsdom for the browser client, node + React Native stubs for the RN app). Do not run npx vitest from the repo root β€” there is no root-level config, so Vitest will pick up all test files without the correct environments and produce misleading failures.

Use the per-package scripts instead:

# Browser client tests (jsdom environment)
npm run test:client

# React Native app tests (node environment + RN stubs)
npm run test:rn

# Both in sequence
npm test

Getting Started (Dev Setup)

⚠️ MVP still in progress β€” setup may change.

  1. Clone the repo.
  2. Start the project:
    # 1) WebSocket server
    cd server && node server.js
    
    # 2) Sample React Native app (or use the hook to access the Fiber tree of your own RN app)
    #    By default the app auto-detects the dev server host via Expo's hostUri.
    #    To override (e.g. on a physical device):
    #    EXPO_PUBLIC_WS_HOST=192.168.1.42 npx expo start
    cd sample-RN-app && npx expo start
    
    # 3) Debugger UI (located at localhost:5173)
    cd client && npm run dev

Roadmap / Planned Features

Shipped

  • Component tree visualization β€” collapsible component hierarchy with changed-state highlighting
  • Snapshot diff view β€” color-coded line-level diff between consecutive snapshots (added / removed / changed)
  • Timeline controls β€” play/pause, speed control (0.5x / 1x / 2x), keyboard navigation

Planned

  • Full fiber tree capture β€” serialize the complete React component tree (props + state at every node), not just stateful nodes; Will's feat/fiber-capture branch
  • Bidirectional time-travel β€” replay state back into the running RN app
  • Expanded metrics β€” fibers updated per commit, event loop lag, app-level profiling
  • Snapshot persistence β€” optionally store history to disk for long debugging sessions
  • Packaging & distribution β€” publish as an npm package for easy setup with any RN project

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

A browser-based debugging tool for React Native applications that visualizes component state changes and performance metrics in real time using a timeline scrubber.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

Packages

 
 
 

Contributors