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

@autotracer/plugin-vite-react18

v1.0.0-alpha.48

Published

Vite plugin for auto-injecting useReactTracer via unplugin

Readme

@autotracer/plugin-vite-react18

Automatic React component tracing for Vite projects.

This Vite plugin automatically injects useReactTracer() hooks into your React components at build time, enabling automatic state and prop labeling without manual instrumentation.

What You Get

  • Reliable component tracking - Marks components for tracing, ensuring they're tracked
  • Perfect variable names - Extract state/prop variable names from your source code
  • Better state change detection - More reliable than fiber-only traversal
  • Development-focused - Control injection per environment
  • Next-gen build tool - Instant HMR during development
  • TypeScript native - Full type safety and inference
  • JSX/TSX support - Automatic React component detection
  • Variable name extraction - See readable state labels in traces
  • Improved change detection - Correctly resolves top level state for nested hooks, complex hooks such as selectors or rtkquery mutations, or proxied states such as react hook form.
  • Pragma support - Fine-grained opt-in/opt-out control at component level
  • Include/Exclude patterns in plugin config for file inclusion/exclusion.
  • Hook naming config to cover edge cases with esoteric hook naming schemes.
    • Default handles ^use[A-Z].*

Installation

pnpm add @autotracer/react18
pnpm add -D @autotracer/plugin-vite-react18

Usage

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { reactTracer } from "@autotracer/plugin-vite-react18";

export default defineConfig(({ mode }) => ({
  plugins: [
    reactTracer.vite({
      inject: mode === "development",
      mode: "opt-out",
      importSource: "@autotracer/react18",
      // Optional: seed the initial output mode before ReactTracer initializes
      // outputMode: "devtools",
      include: ["src/**/*.tsx"],
      exclude: ["**/*.spec.*", "**/*.test.*"],
      // Enable this when using React Server Components (e.g., Next.js App Router)
      // to ensure we only inject into modules marked with "use client".
      // serverComponents: true,
    }),
    react(),
  ],
}));

Configuration Options

inject

Type: boolean Default: true

Controls whether code injection is enabled. Use this to conditionally enable the plugin based on mode or environment:

// Cleaner syntax - inject only in development
reactTracer.vite({
  inject: mode === "development",
  mode: "opt-out",
  // ...other options
});

// Alternative: always include plugin, control via environment
reactTracer.vite({
  mode: "opt-out",
  // ...other options
});
// Then use TRACE_INJECT=0 to disable

When false, the plugin is effectively disabled and no transformations occur. This is useful for:

  • Disabling injection in production builds
  • Conditional tracing based on environment variables
  • Testing with and without tracing enabled

outputMode

Type: "devtools" | "copy-paste" | undefined Default: undefined

When set, the plugin injects a small head-prepend script into index.html to seed the initial output mode before your app runs.

Startup behavior:

  • Sets globalThis.__autoTracerInternal.outputMode to the configured value
  • If globalThis.autoTracer is already available, calls globalThis.autoTracer.setOutputMode(outputMode)

dashboardConfig

Type: Partial<DashboardConfig> | undefined Default: undefined

Enables an in-app dashboard widget with hotkey controls for runtime tracer management. When set, the plugin automatically:

  1. Injects the dashboard configuration as globalThis.__autoTracerDashboardConfig
  2. Imports and mounts the dashboard at page load

Configuration Options:

interface DashboardConfig {
  enabled: boolean; // Enable/disable dashboard (default: true)
  hideByDefault: boolean; // Widget hidden on first load (default: false)
  position: "bottom-right" | "bottom-left" | "top-right" | "top-left"; // Widget position (default: 'bottom-right')
  hotkeys: {
    toggleTracing: string; // Hotkey to start/stop all tracers (default: 'Ctrl+Shift+T')
    toggleDashboard: string; // Hotkey to show/hide widget (default: 'Ctrl+Shift+D')
  };
}

Example:

reactTracer.vite({
  mode: "opt-out",
  dashboardConfig: {
    enabled: true,
    hideByDefault: false, // Show widget immediately
    position: "bottom-right",
    hotkeys: {
      toggleTracing: "Alt+Shift+T", // Start/stop React tracing
      toggleDashboard: "Alt+Shift+D", // Show/hide widget
    },
  },
});

Smart Visibility:

  • If hideByDefault: true, widget is hidden on first load but persists visibility state to localStorage
  • Once a tracer starts (via hotkey or programmatically), widget auto-shows and remembers this state
  • Useful for QA environments where you want the widget available but not intrusive by default

Dual Tracer Support:

  • When both @autotracer/plugin-vite-react18 and @autotracer/plugin-vite-flow are active, the dashboard controls both tracers
  • Alt+Shift+T toggles React tracing and Flow tracing together

See @autotracer/dashboard for full documentation and API reference.

Dev-only behavior

The plugin can be controlled in multiple ways:

  • inject parameter: Set to false to disable injection programmatically
  • TRACE_INJECT=0 environment variable: Disables injection regardless of configuration
  • Production builds: Consider using inject: mode === "development" to ensure tracing only runs during development

Mode vs. pragmas (precedence)

The transformer supports compile-time pragmas to control tracing at the component level.

  • mode: 'opt-in' — Only files matching include are considered. Within those files, use // @trace before individual components to enable injection for that component. Files outside include are not processed.
  • mode: 'opt-out' — All files are eligible except those matching exclude. Use // @trace-disable before individual components to disable tracing for that component.

Precedence rules:

  • File-level exclude always wins: excluded files are never processed.
  • // @trace-disable before a component disables that component only
  • // @trace before a component enables that component (in opt-in mode)

Example pragmas:

// Component-level disable in an opt-out project
// @trace-disable
export function MyComponent() {
  /* Not traced */
}

// Component-level enable in an opt-in project
// @trace
export function AnotherComponent() {
  /* Traced */
}

Hook value labels

You can opt-in to labeling values returned from hooks for nicer console output:

reactTracer.vite({
  labelHooks: ["useState", "useReducer", "useSelector", "useAppSelector"],
  labelHooksPattern: "^use[A-Z].*",
});

This augments built-ins (useState/useReducer) by labeling identifiers assigned from matching hook calls.

Theme File Support

The plugin automatically loads and injects theme files from your project root at build time, enabling personal color and icon customization without code changes.

How It Works

The plugin searches for theme files in your project root directory:

  1. Base theme: *react-theme.json (e.g., react-theme.json, colorblind-react-theme.json)
  2. Light mode override: *react-theme-light.json
  3. Dark mode override: *react-theme-dark.json

Found themes are automatically injected as globalThis.__REACTTRACER_THEME__ before your app loads.

Quick Example

Create react-theme-light.json in your project root:

{
  "definitiveRender": {
    "icon": "🔄",
    "lightMode": { "text": "#0066cc" }
  },
  "error": {
    "icon": "❌",
    "lightMode": { "text": "#cc0000", "background": "#fff5f5" }
  }
}

Add to .gitignore for personal customization:

# Personal react tracer themes
*react-theme.json
*react-theme-light.json
*react-theme-dark.json

Restart your dev server to apply changes.

Theme Priority

Themes merge in this order (later overrides earlier):

  1. Built-in defaults
  2. Theme files (loaded by plugin)
  3. Programmatic config in reactTracer({ colors: {...} })

This allows:

  • Plugin loads team theme: react-theme.json committed to repo
  • Developer adds personal override: my-react-theme-light.json in .gitignore
  • Runtime override: reactTracer({ colors: {...} }) for testing

Complete Guide

See @autotracer/react18 THEME-FILES.md for:

  • Complete theme file structure and schema
  • Light/dark mode configuration
  • Colorblind-friendly themes
  • High-contrast themes
  • Troubleshooting and best practices

Monorepo / Workspace Builds

When a workspace library is compiled by the host app's Rollup pass, the injected import { useReactTracer } from "@autotracer/react18" can't be resolved from the library's own package.json, causing a build error.

The right fix depends on how the library is consumed.

Source libraries (raw TypeScript) → resolve.alias

If the library is consumed as raw .tsx source (no dist/, "noEmit": true), use resolve.alias in the host app to redirect @autotracer/react18 to the host's installed copy. React stays bundled normally; no UMD globals, no CSP risk.

// host-app/vite.config.ts
import { resolve } from "path";

export default defineConfig(({ mode }) => ({
  plugins: [reactTracer.vite({ inject: mode === "development", mode: "opt-out" }), react()],
  resolve: {
    alias: {
      "@autotracer/react18": resolve(__dirname, "../../node_modules/@autotracer/react18"),
    },
  },
}));

Pre-built packages (with own dist/) → buildWithWorkspaceLibs

If the library has its own build step and the host app imports from dist/, use buildWithWorkspaceLibs: true. This externalises React and @autotracer/react18 from the entire app bundle and loads them via injected <script> tags.

⚠️ Side effect: React is removed from your app bundle. If the injected scripts fail to load (CDN outage, CSP, network error) the whole app breaks.

// host-app/vite.config.ts
const isQA = process.env.DEPLOY_ENV === "qa";

export default defineConfig(({ mode }) => ({
  plugins: [
    reactTracer.vite({
      inject: mode === "development" || isQA,
      mode: "opt-out",
      buildWithWorkspaceLibs: isQA, // only for pre-built workspace deps
    }),
    react(),
  ],
}));

Do not use buildWithWorkspaceLibs for source libs — resolve.alias is simpler and has no bundle side-effects.

See the Monorepo Setup guide for a full decision tree, flowcharts, and the CSP / self-hosting walkthrough.

What buildWithWorkspaceLibs does automatically

  1. Externalises @autotracer/react18, react, and react-dom as UMD globals.
  2. Emits the ReactTracer UMD build alongside your output.
  3. Injects <script> tags in index.html to load React, ReactDOM, and ReactTracer before your app bundle.
  4. Creates the React DevTools hook via an inline script so the tracer works in production without the browser extension.

Applies to vite build only — vite dev is unaffected.

Self-Hosting React UMD Files (CSP)

By default, buildWithWorkspaceLibs injects <script> tags pointing to unpkg.com. If your CSP blocks external CDN requests, serve the files from your own origin.

Step 1 — Copy UMD files to your public folder:

node_modules/react/umd/react.production.min.js          → public/vendor/react.production.min.js
node_modules/react-dom/umd/react-dom.production.min.js  → public/vendor/react-dom.production.min.js

Step 2 — Configure the plugin:

reactTracer.vite({
  inject: isQA,
  buildWithWorkspaceLibs: isQA,
  reactUmdSrc: "/vendor/react.production.min.js",
  reactDomUmdSrc: "/vendor/react-dom.production.min.js",
});

Security Considerations

Do Not Enable in Production

The ReactTracer plugin should never be enabled in production environments for the following reasons:

  1. Information Disclosure - The plugin injects code that logs component state, props, and render details to the browser console, potentially exposing:

    • User data and personal information (PII)
    • Authentication state and session details
    • Business logic and application structure
    • Internal component implementation details
  2. Performance Impact - Instrumentation and tracing generate significant overhead that degrades user experience

  3. Bundle Size - Injected hooks and tracing code increase your bundle size unnecessarily

  4. Attack Surface - The DevTools hook and tracing infrastructure are accessible to anyone with console access

Recommended Configuration

Always use environment-based configuration to disable the plugin in production:

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { reactTracer } from "@autotracer/plugin-vite-react18";

export default defineConfig(({ mode }) => {
  const isDev = mode === "development";
  const isQA = process.env.DEPLOY_ENV === "qa";

  return {
    plugins: [
      reactTracer.vite({
        inject: isDev || isQA, // NEVER enable in production
        mode: "opt-out",
        include: ["src/**/*.tsx"],
        exclude: ["**/*.spec.*", "**/*.test.*"],
      }),
      react(),
    ],
  };
});

For TEST/QA builds with workspace libraries:

When using buildWithWorkspaceLibs: true in TEST/QA environments, ensure the plugin inject option is properly configured:

// vite.config.ts - inject option controls whether tracing is enabled
const isQA = process.env.DEPLOY_ENV === "qa";

reactTracer.vite({
  inject: isQA, // Only inject in QA, not production
  buildWithWorkspaceLibs: isQA,
});

Performance Considerations

Build-Time Impact

  • Code transformation: ~10-50ms per file (depends on file size and complexity)
  • Source map generation: ~5-20ms per file
  • Total build overhead: typically < 5% of total build time

Runtime Impact

Per component with injection:

  • Hook execution: ~1-2μs per render
  • State/prop labeling: ~5-10μs per tracked value

Without injection (includeNonTrackedBranches: true):

  • All components processed, significant overhead
  • Not recommended for large applications

Optimization Tips

  1. Use specific include patterns:

    include: ["src/features/**/*.tsx"]; // Only feature components
  2. Exclude test files:

    exclude: ["**/*.spec.*", "**/*.test.*", "**/__tests__/**"];
  3. Use opt-in mode for selective tracing:

    mode: "opt-in"; // Only trace components with // @trace pragma
  4. Disable in production:

    inject: mode === "development";

React Server Components (RSC)

If you're using an RSC-enabled framework (like Next.js App Router), set serverComponents: true in the plugin options. When enabled, the transform will:

  • Treat modules as Server Modules by default

  • Only inject into modules that have the top-level directive:

    "use client";

This prevents injecting client-only hooks where they don't belong. All other transform rules (mode/include/exclude/pragma) still apply to Client Components.

License

MIT