Skip to content

canadianeagle/vite-plugin-component-debugger

Repository files navigation

vite-plugin-component-debugger

npm version npm downloads GitHub license GitHub stars

Build Status Auto Release TypeScript Vite

Buy Me A Coffee Follow on Twitter

A Vite plugin that automatically adds data attributes to JSX/TSX elements during development, making it easier to track, debug, and understand component rendering in your React applications. Perfect for AI-generated code and debugging "which component rendered this?" πŸ€”

Quick Start

# Install
pnpm add -D vite-plugin-component-debugger
# or: npm install --save-dev vite-plugin-component-debugger
# or: yarn add -D vite-plugin-component-debugger
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import componentDebugger from "vite-plugin-component-debugger";

export default defineConfig({
  plugins: [
    componentDebugger(), // ⚠️ IMPORTANT: Must be BEFORE react()
    react(),
  ],
});

⚠️ CRITICAL: componentDebugger() must be placed BEFORE react() plugin, otherwise line numbers will be wrong

What It Does

Before:

// src/components/Button.tsx (line 10)
<button className="btn-primary" onClick={handleClick}>
  Click me
</button>

After (Basic - Default):

<button
  data-dev-id="src/components/Button.tsx:10:2"
  data-dev-name="button"
  data-dev-path="src/components/Button.tsx"
  data-dev-line="10"
  data-dev-file="Button.tsx"
  data-dev-component="button"
  className="btn-primary"
  onClick={handleClick}
>
  Click me
</button>

After (With Metadata Enabled):

componentDebugger({
  includeProps: true,
  includeContent: true
})

// Results in:
<button
  data-dev-id="src/components/Button.tsx:10:2"
  data-dev-name="button"
  data-dev-path="src/components/Button.tsx"
  data-dev-line="10"
  data-dev-file="Button.tsx"
  data-dev-component="button"
  data-dev-metadata="%7B%22className%22%3A%22btn-primary%22%2C%22text%22%3A%22Click%20me%22%7D"
  className="btn-primary"
  onClick={handleClick}
>
  Click me
</button>

Key Benefits

  • πŸ› Debug Faster: Find which component renders any DOM element
  • πŸ“ Jump to Source: Go directly from DevTools to your code
  • 🎯 Stable Testing: Use data attributes for reliable E2E tests
  • ⚑ Zero Runtime Cost: Only runs during development
  • πŸ”§ Smart Exclusions: Automatically skips Fragment and Three.js elements

Configuration

Basic Configuration

componentDebugger({
  enabled: process.env.NODE_ENV === "development", // When to run
  attributePrefix: "data-dev", // Custom prefix
  extensions: [".jsx", ".tsx"], // File types
});

Advanced Configuration

componentDebugger({
  // Core settings
  enabled: process.env.NODE_ENV === "development",
  attributePrefix: "data-dev",
  extensions: [".jsx", ".tsx"],

  // Content capture (disabled by default for performance)
  includeProps: true, // Enable to capture component props in data-dev-metadata
  includeContent: true, // Enable to capture text content in data-dev-metadata

  // Element exclusions
  excludeElements: ["Fragment", "React.Fragment"],
  customExcludes: new Set(["mesh", "group", "camera"]), // Three.js elements
});

All Configuration Options

Option Type Default Description
enabled boolean true Enable/disable the plugin
attributePrefix string 'data-dev' Prefix for data attributes
extensions string[] ['.jsx', '.tsx'] File extensions to process
includeProps boolean false Include component props in metadata
includeContent boolean false Include text content in metadata
excludeElements string[] ['Fragment', 'React.Fragment'] Elements to exclude
customExcludes Set<string> Three.js elements Custom elements to exclude

Use Cases

1. Development Debugging (Simple)

Find components in the DOM:

// In browser console
document.querySelectorAll('[data-dev-component="Button"]');
console.log("Button locations:", [...$$('[data-dev-path*="Button"]')]);

2. E2E Testing (Intermediate)

Stable selectors for tests:

// Cypress
cy.get('[data-dev-component="SubmitButton"]').click();
cy.get('[data-dev-path*="LoginForm"]').should("be.visible");

// Playwright
await page.click('[data-dev-component="SubmitButton"]');
await expect(page.locator('[data-dev-path*="LoginForm"]')).toBeVisible();

3. Visual Debugging Tools (Advanced)

Build custom debugging overlays:

// Show component boundaries on hover
document.addEventListener("mouseover", (e) => {
  const target = e.target;
  if (target.dataset?.devComponent) {
    target.style.outline = "2px solid red";
    console.log(`Component: ${target.dataset.devComponent}`);
    console.log(`Location: ${target.dataset.devPath}:${target.dataset.devLine}`);
  }
});

4. Performance Monitoring (Expert)

Track component render activity:

const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.type === "childList") {
      mutation.addedNodes.forEach((node) => {
        if (node.dataset?.devId) {
          console.log(`Component rendered: ${node.dataset.devId}`);
        }
      });
    }
  });
});

observer.observe(document.body, { childList: true, subtree: true });

Advanced Features

Environment-Specific Setup

// Different configs per environment
const isDev = process.env.NODE_ENV === "development";
const isStaging = process.env.NODE_ENV === "staging";

export default defineConfig({
  plugins: [
    componentDebugger({
      enabled: isDev || isStaging,
      attributePrefix: isStaging ? "data-staging" : "data-dev",
      includeProps: isDev, // Enable metadata in development
      includeContent: isDev, // Enable content capture in development
    }),
    react(),
  ],
});

React Three Fiber Support

Automatically excludes Three.js elements:

// Default exclusions
componentDebugger({
  customExcludes: new Set([
    "mesh",
    "group",
    "scene",
    "camera",
    "ambientLight",
    "directionalLight",
    "pointLight",
    "boxGeometry",
    "sphereGeometry",
    "planeGeometry",
    "meshBasicMaterial",
    "meshStandardMaterial",
    // ... and many more
  ]),
});

// To include Three.js elements
componentDebugger({
  customExcludes: new Set(), // Empty set = tag everything
});

TypeScript Support

Full type definitions included:

import componentDebugger, { type TagOptions } from "vite-plugin-component-debugger";

const config: TagOptions = {
  enabled: true,
  attributePrefix: "data-track",
};

export default defineConfig({
  plugins: [componentDebugger(config), react()],
});

Build Performance & Statistics

πŸ“Š Component Debugger Statistics:
   Total files scanned: 45
   Files processed: 32
   Elements tagged: 287

Performance optimizations:

  • Efficient AST traversal with caching
  • Minimal HMR impact
  • Automatically skips node_modules
  • Only runs during development

Troubleshooting

⚠️ Line numbers are wrong/offset by ~19?

  1. Most common issue: Plugin order is wrong
  2. Fix: Move componentDebugger() BEFORE react() in Vite config
  3. Cause: React plugin adds ~19 lines of imports/HMR setup
// ❌ WRONG - Line numbers will be offset
export default defineConfig({
  plugins: [
    react(), // Transforms code first, adds ~19 lines
    componentDebugger(), // Gets wrong line numbers
  ],
});

// βœ… CORRECT - Accurate line numbers
export default defineConfig({
  plugins: [
    componentDebugger(), // Processes original source first
    react(), // Transforms after tagging
  ],
});

Elements not being tagged?

  1. Check file extension is in extensions
  2. Verify element isn't in exclusion lists
  3. Ensure plugin is enabled
  4. Verify plugin order (componentDebugger before react)

Build performance issues?

  1. Limit extensions scope
  2. Add more elements to excludeElements
  3. Keep includeProps/includeContent disabled (default) for better performance and less noise in the DOM

Attributes not in production?

componentDebugger({
  enabled: process.env.NODE_ENV !== "production",
});

Debug line number issues:

componentDebugger({
  debug: true, // Shows processed code and line numbers
  enabled: true,
});

Development & Contributing

Auto-Release Workflow

πŸš€ Every commit to main triggers automatic release:

Commit Message β†’ Version Bump:

  • BREAKING CHANGE: or major: β†’ Major (1.0.0 β†’ 2.0.0)
  • feat: or feature: or minor: β†’ Minor (1.0.0 β†’ 1.1.0)
  • Everything else β†’ Patch (1.0.0 β†’ 1.0.1)

Example commit messages:

# Major version (breaking changes)
git commit -m "BREAKING CHANGE: removed deprecated API"
git commit -m "major: complete rewrite of plugin interface"

# Minor version (new features)
git commit -m "feat: add TypeScript 5.0 support"
git commit -m "feature: new configuration option for props"
git commit -m "minor: add custom exclude patterns"

# Patch version (bug fixes, docs, chores)
git commit -m "fix: resolve memory leak in transformer"
git commit -m "docs: update README examples"
git commit -m "chore: update dependencies"

# Skip release
git commit -m "docs: fix typo [skip ci]"

What happens automatically:

  1. Tests run, package builds
  2. Version bump based on commit message
  3. GitHub release created with changelog
  4. Package published to npm

Setup auto-publishing:

  1. Get NPM token: npm token create --type=automation
  2. Add to GitHub repo: Settings β†’ Secrets β†’ NPM_TOKEN
  3. Commit to main branch to trigger first release

Contributing

  1. Fork and clone
  2. pnpm install
  3. Make changes and add tests
  4. pnpm run check (lint + test + build)
  5. Commit with semantic message (see above)
  6. Open PR

See .github/COMMIT_CONVENTION.md for examples.

Development Setup

git clone https://github.com/yourusername/vite-plugin-component-debugger.git
cd vite-plugin-component-debugger
pnpm install
pnpm run test     # Run tests
pnpm run build    # Build package
pnpm run check    # Full validation

Author & Support

Tonye Brown - Builder, Front-end developer, designer, and performance optimization expert crafting immersive web experiences. Also a Music Producer and Artist.

Connect:

Support This Project:

  • ⭐ Star this repository
  • β˜• Buy me a coffee
  • πŸ’ Sponsor on GitHub
  • πŸ› Report issues or suggest features
  • 🀝 Contribute code via pull requests
  • πŸ“’ Share with other developers

License

MIT Β© Tonye Brown


Made with ❀️ by Tonye Brown

Inspired by lovable-tagger, enhanced for the Vite ecosystem.

GitHub Website LinkedIn

⭐ Star this repo if it helped you!