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-babel-flow

v1.0.0-alpha.33

Published

Babel plugin for automatic function flow tracing with try/catch/finally injection

Readme

@autotracer/plugin-babel-flow

Babel plugin for automatic function flow tracing with try/catch/finally injection.

Automatically instruments your functions to track entry, exit, parameters, return values, and exceptions. Works with any Babel-based build system including Next.js, Create React App, and custom Webpack/Rollup setups.

What You Get

  • Zero-config function instrumentation - Automatically wraps functions with tracing code
  • Selective targeting - Choose which functions to instrument via patterns
  • Try/catch/finally injection - Safe exception tracking without breaking error handling
  • Return value tracing - Captures and logs function return values
  • Dormant mode support - Integrates with @autotracer/flow runtime control
  • Build-time transformation - Zero runtime overhead for transformation logic

Who This Is For

If you're using Next.js, Create React App, or any Babel-based build, this is your plugin.

For Vite, use @autotracer/plugin-vite-flow instead.

Installation

npm install --save-dev @autotracer/plugin-babel-flow
npm install @autotracer/flow @autotracer/logger

Note: @autotracer/logger is a required dependency of @autotracer/flow. @babel/core is a peer dependency (usually already installed in Babel-based projects).

For pnpm users: Add auto-install-peers=true to your .npmrc file to automatically install peer dependencies:

# .npmrc
auto-install-peers=true

Quickstart

Next.js (App Router or Pages Router)

// babel.config.js or .babelrc
module.exports = {
  plugins: [
    ["@autotracer/plugin-babel-flow", {
      include: {
        paths: ["**/src/**", "**/app/**"],
        functions: ["handle*", "on*", "fetch*"]
      }
    }]
  ]
};

Then import the runtime in your app:

// app/layout.tsx (App Router) or pages/_app.tsx (Pages Router)
"use client";  // App Router only

import "@autotracer/flow/runtime";

export default function RootLayout({ children }) {
  return children;
}

Create React App

// .babelrc or babel.config.js
{
  "plugins": [
    ["@autotracer/plugin-babel-flow", {
      "include": {
        "paths": ["src/**"],
        "functions": ["*"]  // Instrument all functions in src/
      }
    }]
  ]
}

Import the runtime in your entry point:

// src/index.tsx
import "@autotracer/flow/runtime";
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")!).render(<App />);

Custom Babel Setup

// babel.config.js
module.exports = {
  presets: ["@babel/preset-env", "@babel/preset-typescript"],
  plugins: [
    ["@autotracer/plugin-babel-flow", {
      tracerName: "__flowTracer",
      logExceptions: true,
      exceptionLogLevel: "debug",
      include: {
        paths: ["src/**/*.ts", "src/**/*.tsx"],
        functions: ["handle*", "process*", "calculate*"]
      },
      exclude: {
        paths: ["**/*.test.ts", "**/*.spec.ts"],
        functions: ["render*"]  // Don't instrument React render methods
      }
    }]
  ]
};

Configuration Options

interface BabelPluginFlowConfig {
  /** Name of the global tracer variable (default: "__flowTracer") */
  tracerName?: string;

  /** Log exceptions to console when caught (default: true) */
  logExceptions?: boolean;

  /** Log level for exception logging (default: "debug") */
  exceptionLogLevel?: "debug" | "warn" | "error";

  /** Files and functions to include */
  include?: {
    /** Glob patterns for file paths */
    paths?: string[];

    /** Function name patterns (glob or regex, e.g. "handle*", /^on[A-Z]/) */
    functions?: Array<string | RegExp>;
  };

  /** Files and functions to exclude (takes precedence over include) */
  exclude?: {
    /** Glob patterns for file paths */
    paths?: string[];

    /** Function name patterns (glob or regex) */
    functions?: Array<string | RegExp>;
  };
}

Default Configuration

{
  tracerName: "__flowTracer",
  logExceptions: true,
  exceptionLogLevel: "debug",
  include: {},   // No filters - all functions instrumented
  exclude: {}    // Nothing excluded
}

Note: The Babel plugin doesn't have enabled or runtimeControlled options. To conditionally enable the plugin, use Babel's environment-based configuration or simply add/remove it from your plugins array. For runtime control, manually import @autotracer/flow/runtime in your app.

How It Works

Before Transformation

function calculateTotal(prices: number[]): number {
  const sum = prices.reduce((acc, price) => acc + price, 0);
  return sum;
}

After Transformation

function calculateTotal(prices: number[]): number {
  const __h0 = __flowTracer.enter("calculateTotal", prices);
  try {
    const sum = prices.reduce((acc, price) => acc + price, 0);
    const __returnValue = sum;
    __flowTracer.exit(__h0, __returnValue);
    return __returnValue;
  } catch (__error) {
    __flowTracer.exit(__h0);
    throw __error;
  }
}

What Gets Instrumented

The plugin instruments:

  • ✅ Named function declarations
  • ✅ Arrow function expressions (when assigned to variables)
  • ✅ Function expressions
  • ✅ Object method shorthand
  • ✅ Class methods (instance and static)
  • ❌ Anonymous inline callbacks (too noisy)
  • ❌ IIFE expressions (immediately invoked)

Filtering Logic

Functions are instrumented if they match ALL of these:

  1. Path matches include.paths AND doesn't match exclude.paths
  2. Function name matches include.functions AND doesn't match exclude.functions

Pattern Examples

{
  include: {
    paths: ["src/**"],           // All files in src/
    functions: ["handle*", "on*"] // handleClick, onClick, etc.
  },
  exclude: {
    paths: ["src/**/*.test.ts"],  // Skip test files
    functions: ["handleError"]    // Skip specific function
  }
}

Usage Patterns

Event Handlers Only

{
  include: {
    paths: ["src/**/*.tsx"],
    functions: ["handle*", "on*"]  // handleClick, onSubmit, etc.
  }
}

Business Logic Only

{
  include: {
    paths: ["src/services/**", "src/utils/**"],
    functions: ["*"]  // All functions in these folders
  },
  exclude: {
    functions: ["render*", "use*"]  // Skip React render/hooks
  }
}

Specific File + Specific Functions

{
  include: {
    paths: ["src/auth/**"],
    functions: ["login*", "logout*", "verify*"]
  }
}

Development Only

To only instrument in development, conditionally add the plugin:

// babel.config.js
module.exports = {
  plugins: [
    ...(process.env.NODE_ENV === 'development' ? [
      ["@autotracer/plugin-babel-flow", {
        include: {
          paths: ["src/**"],
          functions: ["*"]
        }
      }]
    ] : [])
  ]
};

Runtime Control Integration

Dormant Mode (Recommended for TEST/QA)

The Babel plugin always instruments functions. To use dormant mode (tracing disabled until activated), import the runtime control:

// Your app entry point
import "@autotracer/flow/runtime";

// Now developers can activate in browser console:
// window.startFlowTracing()

This is safe for TEST/QA environments because:

  • Functions are instrumented but produce no output by default
  • Logger is set to "off" (zero console overhead)
  • Only activates when developer explicitly enables it

Always Active (Development)

If you don't import the runtime, functions produce immediate output:

// Your app entry point
import "@autotracer/flow";  // Direct import, not /runtime

// All instrumented functions immediately log to console

Exception Logging

The plugin wraps function bodies in try/catch/finally to safely log exceptions:

// Your code
function divide(a: number, b: number): number {
  if (b === 0) throw new Error("Division by zero");
  return a / b;
}

// Transformed (simplified)
function divide(a: number, b: number): number {
  const __h0 = __flowTracer.enter("divide", a, b);
  try {
    if (b === 0) throw new Error("Division by zero");
    const __returnValue = a / b;
    __flowTracer.exit(__h0, __returnValue);
    return __returnValue;
  } catch (__error) {
    // Exception is logged here before re-throwing
    __flowTracer.exit(__h0);
    throw __error;
  }
}

Console output when exception occurs:

divide
  params: 10 0
  💥 Exception in divide: Error: Division by zero
    at divide (math.ts:23:15)
    ...
  divide (elapsed: 0.8ms)

The exception is logged and then re-thrown, preserving your app's error handling.

Performance Considerations

Build Time

  • First build: Adds ~100-500ms depending on codebase size
  • Subsequent builds: Cached, minimal overhead
  • Filtering helps: Only instrumenting targeted functions reduces transformation time

Runtime Overhead

Dormant mode (runtimeControlled: true):

  • Function call overhead: ~0.1μs (just enter/exit calls)
  • No console I/O
  • Production-safe

Active mode (runtimeControlled: false or activated):

  • Console.group/log overhead: ~50-100μs per function
  • Not recommended for production

Recommendations

  1. Production: Use dormant mode, instrument broadly
  2. Development: Either always-active or dormant mode
  3. Filter aggressively: Only instrument what you need to debug

Integration with TypeScript

The plugin works seamlessly with TypeScript:

// babel.config.js
module.exports = {
  presets: [
    ["@babel/preset-env", { targets: { node: "current" } }],
    "@babel/preset-typescript"
  ],
  plugins: [
    ["@autotracer/plugin-babel-flow", {
      include: {
        paths: ["src/**/*.ts", "src/**/*.tsx"]
      }
    }]
  ]
};

TypeScript types are preserved in the transformation.

Troubleshooting

Plugin not running

  1. Check Babel is configured correctly (babel.config.js or .babelrc)
  2. Verify enabled: true in plugin options
  3. Check your build tool is using Babel (some tools skip it)

Functions not instrumented

  1. Check file path matches include.paths patterns
  2. Check function name matches include.functions patterns
  3. Verify function isn't in exclude patterns
  4. Anonymous functions and IIFEs aren't instrumented

No console output

If runtimeControlled: true:

  1. Import the runtime: import "@autotracer/flow/runtime"
  2. Activate in browser console: window.startFlowTracing()

If runtimeControlled: false:

  1. Check browser console for errors
  2. Verify @autotracer/flow is installed
  3. Check logger isn't set to "off"

Build errors

"__flowTracer is not defined":

  • Add import "@autotracer/flow" to your entry point
  • Or enable runtimeControlled: true for automatic injection

Babel transform errors:

  • Check your Babel preset configuration
  • Ensure TypeScript preset runs before this plugin
  • Check for syntax errors in your source files

Next.js specific issues

App Router: Make sure runtime import is in a "use client" component:

// app/layout.tsx
"use client";
import "@autotracer/flow/runtime";

Pages Router: Import in pages/_app.tsx:

// pages/_app.tsx
import "@autotracer/flow/runtime";

Advanced Usage

Conditional Instrumentation

// babel.config.js
const isDevelopment = process.env.NODE_ENV === "development";
const isDebugBuild = process.env.DEBUG === "true";

module.exports = {
  plugins: [
    // Only include plugin in dev or debug builds
    ...(isDevelopment || isDebugBuild ? [
      ["@autotracer/plugin-babel-flow", {
        include: {
          paths: isDevelopment
            ? ["src/**"]           // All files in development
            : ["src/services/**"]  // Only services in debug builds
        }
      }]
    ] : [])
  ]
};

Multiple Configurations

You can use different plugin configs per environment:

module.exports = {
  env: {
    development: {
      plugins: [
        ["@autotracer/plugin-babel-flow", {
          include: { paths: ["src/**"], functions: ["*"] }
        }]
      ]
    },
    test: {
      plugins: [
        ["@autotracer/plugin-babel-flow", {
          include: { paths: ["src/services/**"], functions: ["fetch*", "process*"] }
        }]
      ]
    },
    production: {
      plugins: []  // No flow tracing in production
    }
  }
};

Comparison with Vite Plugin

| Feature | Babel Plugin | Vite Plugin | |---------|-------------|-------------| | Build System | Babel-based (Next.js, CRA, Webpack) | Vite only | | Transformation | AST traversal | Babel via Vite | | Runtime Injection | Manual import | Automatic HTML injection | | Configuration | Babel config | Vite config | | Performance | Slower (more comprehensive) | Faster (optimized for Vite) |

Use Babel plugin for Next.js/CRA, Vite plugin for Vite-based apps.

Architecture

graph TD
    A[Source Code] --> B[Babel Parser]
    B --> C[AST Traversal]
    C --> D{Match Filters?}
    D -->|Yes| E[Inject Instrumentation]
    D -->|No| F[Skip]
    E --> G[Wrap in try/catch/finally]
    G --> H[Add enter/exit calls]
    H --> I[Transform return statements]
    I --> J[Code Generation]
    F --> J
    J --> K[Instrumented Code]

License

MIT