@autotracer/plugin-vite-flow
v1.0.0-alpha.35
Published
Vite plugin for automatic function flow tracing via Babel transformation
Readme
@autotracer/plugin-vite-flow
Vite plugin for automatic function flow tracing with dormant mode and runtime control.
Automatically instruments your functions to track entry, exit, parameters, return values, and exceptions. Optimized for Vite's build pipeline with automatic HTML injection for seamless integration.
What You Get
- Zero-config function instrumentation - Automatically wraps functions with tracing code
- Automatic runtime injection - No manual imports needed in dormant mode
- Selective targeting - Choose which functions to instrument via patterns
- Try/catch/finally injection - Safe exception tracking without breaking error handling
- Dormant mode - Zero console overhead until activated via browser console
- Build-time transformation - Leverages Vite's fast build pipeline
Who This Is For
If you're using Vite (vanilla, React, Vue, Svelte, etc.), this is your plugin.
For Next.js, Create React App, or other Babel-based builds, use @autotracer/plugin-babel-flow instead.
Installation
pnpm add @autotracer/flow @autotracer/logger
pnpm add -D @autotracer/plugin-vite-flow @babel/core @babel/preset-typescriptNote: @autotracer/logger is a required dependency of @autotracer/flow. The Babel packages (@babel/core and @babel/preset-typescript) are peer dependencies required for code transformation.
For pnpm users: Add auto-install-peers=true to your .npmrc file to automatically install peer dependencies:
# .npmrc
auto-install-peers=trueMonorepo / Workspace Setup
When using the plugin from a local workspace (e.g., in a monorepo), add Vite aliases:
// vite.config.ts
import path from "path";
export default defineConfig({
resolve: {
alias: {
"@autotracer/flow/runtime": path.resolve(
__dirname,
"../../packages/auto-tracer-flow/dist/runtime.js",
),
"@autotracer/flow": path.resolve(
__dirname,
"../../packages/auto-tracer-flow",
),
"@autotracer/logger": path.resolve(
__dirname,
"../../packages/auto-tracer-logger",
),
},
},
plugins: [
flowTracer({
/* ... */
}),
],
});Important: The /runtime alias must come before the base @autotracer/flow alias.
Quickstart
Dormant Mode (Recommended for TEST/QA)
Start with tracing disabled, activate on-demand via browser console:
// vite.config.ts
import { defineConfig } from "vite";
import { flowTracer } from "@autotracer/plugin-vite-flow";
export default defineConfig({
plugins: [
flowTracer({
enabled: true,
runtimeControlled: true, // Start dormant
include: {
paths: ["**/src/**"],
functions: ["handle*", "on*", "process*"],
},
}),
],
});No manual imports needed! The plugin automatically injects the runtime. Just open browser console:
// Activate tracing
globalThis.autoTracer.flowTracer.start();
// Deactivate tracing
globalThis.autoTracer.flowTracer.stop();Always Active Mode (Local Development)
Immediate console output for all instrumented functions:
// vite.config.ts
import { defineConfig } from "vite";
import { flowTracer } from "@autotracer/plugin-vite-flow";
export default defineConfig({
plugins: [
flowTracer({
enabled: true,
runtimeControlled: false, // Always active
include: {
paths: ["**/src/**"],
functions: ["*"], // All functions
},
}),
],
});Functions produce console output immediately - no browser console commands needed.
Production Builds
Disable flow tracing completely:
// vite.config.ts
import { defineConfig } from "vite";
import { flowTracer } from "@autotracer/plugin-vite-flow";
const isDev = process.env.NODE_ENV === "development";
const isQA = process.env.DEPLOY_ENV === "qa";
export default defineConfig({
plugins: [
flowTracer({
enabled: isDev || isQA, // Disabled in production
runtimeControlled: isQA, // Dormant in QA, active in dev
include: {
paths: ["**/src/**"],
},
}),
],
});Configuration Options
interface FlowTracerViteOptions {
/** Enable/disable the plugin (default: true) */
enabled?: boolean;
/** Start dormant, activate via globalThis.autoTracer.flowTracer.start() (default: false) */
runtimeControlled?: boolean;
/** Set output formatting at startup (default: unset) */
outputMode?: "devtools" | "copy-paste";
/** Name of the injected local tracer identifier (default: "__flowTracer") */
tracerName?: string;
/** Log exceptions in catch blocks (default: true) */
logExceptions?: boolean;
/** Log level for exceptions (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) */
functions?: Array<string | RegExp>;
};
/** Files and functions to exclude */
exclude?: {
/** Glob patterns for file paths */
paths?: string[];
/** Function name patterns (glob or regex) */
functions?: Array<string | RegExp>;
};
}Default Configuration
{
enabled: true,
runtimeControlled: false,
tracerName: "__flowTracer",
logExceptions: true,
exceptionLogLevel: "debug",
include: {}, // No filters - all functions instrumented
exclude: {} // Nothing excluded
}Filtering: Include and Exclude Patterns
Control which functions get instrumented using include and exclude patterns:
Function Patterns
Match functions by name using glob patterns, regular expressions, or exact strings:
flowTracer({
include: {
functions: ["handle*", "on*", /^process[A-Z]/], // Event handlers and processors
},
exclude: {
functions: ["handleError", "onInit"], // Skip specific functions
},
});Pattern matching:
- Glob patterns:
"handle*","*Click","on*Event" - Regular expressions:
/^handle[A-Z]/,/^on[A-Z]\w+$/ - Exact strings:
"handleSubmit","onClick"
File Path Patterns
Instrument only files in specific directories:
flowTracer({
include: {
paths: ["**/src/**"], // Only instrument source files
},
exclude: {
paths: ["**/src/utils/**", "**/src/config/**"], // Skip utilities and config
},
});Path patterns use glob syntax:
**/src/**- All files under anysrcdirectory**/components/**/*.tsx- All TSX files in anycomponentsdirectorysrc/features/**- Files undersrc/features
Combined Filtering
Both function and path patterns can be used together:
flowTracer({
include: {
paths: ["**/src/features/**"],
functions: ["handle*", "process*"],
},
exclude: {
functions: ["handleError", "processLogs"],
},
});This configuration:
- ✅ Instruments
handleSubmitinsrc/features/form/FormHandler.ts - ❌ Skips
handleError(excluded function) - ❌ Skips
fetchData(not in include functions) - ❌ Skips any function in
src/utils/(not in include paths)
Usage Patterns
Event Handlers Only
flowTracer({
include: {
paths: ["src/**/*.tsx"],
functions: ["handle*", "on*"],
},
});Business Logic Only
flowTracer({
include: {
paths: ["src/services/**", "src/utils/**"],
functions: ["*"],
},
exclude: {
functions: ["render*", "use*"], // Skip React render/hooks
},
});Feature-Specific Tracing
flowTracer({
include: {
paths: ["src/features/checkout/**"],
functions: ["calculate*", "validate*", "process*"],
},
});How It Works
HTML Injection
When runtimeControlled: true, the plugin automatically injects into your HTML:
<script type="module">
import "@autotracer/flow";
import "@autotracer/flow/runtime";
</script>When runtimeControlled: false:
<script type="module">
import "@autotracer/flow";
</script>Code Transformation
The plugin uses Babel to transform your functions:
Before:
function calculateTotal(prices: number[]): number {
const sum = prices.reduce((acc, price) => acc + price, 0);
return sum;
}After:
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;
}
}Console Output
Function Calls
handleAdd
add
params: 5 3
returned: 8
add (elapsed: 0.5ms)
handleAdd (elapsed: 1.2ms)Exceptions
divide
params: 10 0
💥 Exception in divide: Error: Division by zero
at divide (App.tsx:64:13)
at safeDivide (App.tsx:87:12)
...
divide (elapsed: 1.4ms)Performance Considerations
Dormant Mode
When logger is "off" (dormant mode):
- Function call overhead: ~0.1μs (just enter/exit calls)
- No console I/O
- No string formatting
- TEST/QA-safe
Active Mode
When tracing is enabled:
- Console.group nesting: ~50-100μs per function
- Parameter stringification: varies by complexity
- Not recommended for production
Recommendations
- Local Dev: Either always-active or dormant mode
- TEST/QA: Dormant mode (
runtimeControlled: true) - Production: Disabled (
enabled: false)
Security Considerations
Do Not Use in Production
Flow tracing should never be enabled in production because:
- Information Disclosure - Logs function parameters, return values, and exceptions (credentials, PII, tokens)
- Performance Impact - Console I/O degrades user experience
- Attack Surface -
window.autoTracer.flowTracer.start()is accessible to anyone with console access
Recommended Setup by Environment
const isDev = process.env.NODE_ENV === "development";
const isQA = process.env.DEPLOY_ENV === "qa";
export default defineConfig({
plugins: [
flowTracer({
enabled: isDev || isQA, // Never in production
runtimeControlled: isQA, // Dormant in QA, active in dev
include: { paths: ["**/src/**"] },
}),
],
});Troubleshooting
No logs appearing
- Check if runtime control is enabled:
window.autoTracer.flowTracer.isEnabled() - Activate tracing:
window.autoTracer.flowTracer.start() - Verify functions are instrumented (check
include/excludeconfig)
"Flow tracing runtime control ready" message not appearing
The runtime import isn't being loaded:
- Check
runtimeControlled: truein config - Verify HTML injection is working (dev mode)
- Check browser console for import errors
Functions not traced
- File path doesn't match
include.pathspatterns - Function name doesn't match
include.functionspatterns - Function matches
excludepatterns - Anonymous functions aren't instrumented
Build errors
"Cannot find module '@babel/preset-typescript'":
- The plugin's dependencies may not have installed correctly
- Manually install:
pnpm add -D @babel/core @babel/preset-typescript - This can happen in monorepos or with certain package manager configurations
"__flowTracer is not defined":
- Set
enabled: falseorruntimeControlled: true - The plugin should auto-inject, but check HTML output
Babel transform errors:
- Check your TypeScript configuration
- Verify file extensions match Vite's processing rules
Too much output
Narrow your filters:
flowTracer({
include: {
functions: ["handle*", "on*"], // Only event handlers
},
});Integration with React Plugin
If using @autotracer/plugin-vite-react18 for React lifecycle logging, the flow plugin must come first:
import { flowTracer } from "@autotracer/plugin-vite-flow";
import { reactTracer } from "@autotracer/plugin-vite-react18";
export default defineConfig({
plugins: [
flowTracer({
/* ... */
}), // First
reactTracer({
/* ... */
}), // Second
],
});Advanced Usage
Environment-Specific Configuration
const isDev = process.env.NODE_ENV === "development";
const isQA = process.env.DEPLOY_ENV === "qa";
const isTest = process.env.NODE_ENV === "test";
export default defineConfig({
plugins: [
flowTracer({
enabled: isDev || isQA || isTest,
runtimeControlled: isQA, // Only QA uses dormant mode
include: {
paths: isDev
? ["**/src/**"] // All files in dev
: ["**/src/services/**"], // Only services in QA/test
functions: isDev
? ["*"] // All functions in dev
: ["fetch*", "process*"], // Only specific in QA/test
},
}),
],
});Conditional Plugin Loading
export default defineConfig({
plugins: [
...(process.env.ENABLE_TRACING
? [
flowTracer({
runtimeControlled: true,
include: { paths: ["**/src/**"] },
}),
]
: []),
],
});Comparison with Babel Plugin
| Feature | Vite Plugin | Babel Plugin |
| ------------------- | ------------------------ | -------------------------- |
| Build System | Vite only | Babel-based (Next.js, CRA) |
| Runtime Injection | Automatic HTML injection | Manual import |
| Configuration | Vite config | Babel config |
| Performance | Optimized for Vite | Standard Babel |
| enabled option | ✅ Yes | ❌ No |
| runtimeControlled | ✅ Yes | ❌ No (manual) |
Use Vite plugin for Vite projects, Babel plugin for Next.js/CRA.
Architecture
graph TD
A[Vite Build] --> B[Plugin: transformIndexHtml]
B --> C{runtimeControlled?}
C -->|Yes| D[Inject flow + runtime]
C -->|No| E[Inject flow only]
F[Source Files] --> G[Plugin: transform]
G --> H[Babel Transformation]
H --> I[Instrumented Code]
D --> J[Browser]
E --> J
I --> J
J --> K{Runtime Mode}
K -->|Dormant| L[window.autoTracer.flowTracer.start]
K -->|Active| M[Immediate Output]License
MIT
