npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@artshin/expo-perf-recorder

v0.0.2

Published

Continuous background React profiler for Expo / React Native (dev-only). Captures React DevTools profiling dumps in JS and persists, analyses and aggregates them natively, off the JS thread.

Readme

@artshin/expo-perf-recorder

npm License: MIT

Continuous, dev-only background React profiler for Expo / React Native apps, shipped as a self-contained Expo module (autolinked native Kotlin + Swift). It records the same data the React DevTools profiler captures (getProfilingData() V5 exports), but automatically and on an interval — then persists, analyses, and aggregates it natively, off the JS thread, so stats are available on demand.

The companion Rozenite DevTools panel + agent tools live in @artshin/rozenite-perf-recorder.

Install

npx expo install @artshin/expo-perf-recorder

Expo autolinking picks up the native module from node_modules — no manual linking. Rebuild the dev client / run expo prebuild so the native code is compiled in.

How it works

| Layer | Where | Responsibility | |-------|-------|----------------| | Capture | JS (src/capture.ts) | Taps __REACT_DEVTOOLS_GLOBAL_HOOK__, runs a continuous loop: every intervalMs it stops the profiling window, ships the V5 export to native, and re-arms a fresh window (so in-memory commit data never grows unbounded). | | Persist + analyse + stats | Native (Kotlin / Swift) | Parses each dump on a background thread, ring-buffers raw dumps to disk, and folds results into rolling stats that survive Fast Refresh. | | Stats UI | JS (src/overlay/PerfOverlay.tsx) | Floating dev overlay. A richer Rozenite devtools panel ships in @artshin/rozenite-perf-recorder. |

Capture must run in the app's JS runtime — the timing data lives in React's in-memory fiber tree, reachable only through the devtools hook. Everything else is native and off-thread.

Usage

Zero-integration (recommended)

Add one side-effect import to your app entry (index.ts):

import "@artshin/expo-perf-recorder/auto"; // dev-only; no-op in production

That's it — the loop arms itself once the devtools agent attaches.

Show live stats

Mount the overlay near the app root (dev branch only):

import { PerfOverlay } from "@artshin/expo-perf-recorder";
// ...
{__DEV__ && <PerfOverlay />}

Tap the pill to expand; long-press to clear stats.

Programmatic

import {
  startPerfRecorder,
  stopPerfRecorder,
  getPerfStats,
  clearPerfData,
} from "@artshin/expo-perf-recorder";

await startPerfRecorder({ intervalMs: 8000, mainRendererOnly: true, maxDumps: 50 });
const stats = await getPerfStats(); // PerfStats
await stopPerfRecorder();
await clearPerfData();

Config

| Option | Default | Notes | |--------|---------|-------| | intervalMs | 10000 | Window length / ship cadence. Bounds memory. | | mainRendererOnly | true | Skip secondary reconcilers (e.g. Skia) — they have destabilised devtools attach on this app. | | maxDumps | 50 | Raw dumps retained in the native disk ring buffer. |

Caveats

  • Dev-only. Guarded by __DEV__; profiling mode adds per-commit overhead and skews absolute numbers — read it for trends/regressions, not budgets.
  • Names come from the in-app DevTools operations decoder (src/operations.ts), injected into each dump's snapshots before shipping; commitData.updaters is the secondary source. Requires the devtools agent attached (see :8097 caveat).
  • Rolling fiber stats are keyed by name, not id, because element ids reset on every JS reload.
  • Raw dumps land in the app cache dir (<cache>/perf-recorder/), newest-last.

Companion panel

@artshin/rozenite-perf-recorder is a standalone Rozenite DevTools panel + agent tools that talk to this module's native side by name (requireNativeModule("PerfRecorder")). It surfaces the same rolling stats in a Rozenite panel and exposes get-stats / clear / list-dumps / get-dump agent tools. See that package's README.