# Macaly Tagger

A webpack loader that adds location metadata to JSX elements for development debugging. This loader automatically injects `data-macaly-loc` and `data-macaly-name` attributes into your JSX elements, making it easy to trace elements back to their source code location.

## Features

- 🎯 **Precise location tracking**: Shows exact file, line, and column for each JSX element
- 🚀 **Zero runtime overhead**: Only runs in development mode
- 🔧 **Easy integration**: Simple webpack configuration
- 📦 **TypeScript support**: Works with both `.jsx` and `.tsx` files
- 🚫 **Smart filtering**: Automatically excludes `node_modules`, React Fragments, and non-DOM elements
- 🎮 **Custom renderer support**: Compatible with React Three Fiber and other custom renderers via `ignorePackages` option

## Installation

```bash
npm install --save-dev macaly-tagger
```

The loader has the following dependencies that will be installed automatically:

- `@babel/parser`
- `magic-string`
- `estree-walker`

## Usage

### Next.js Setup

#### For Next.js 15.3.0+ with Turbopack

Configure your `next.config.js`:

```js
/** @type {import('next').NextConfig} */
const nextConfig = {
  turbopack: {
    rules: {
      "*.{jsx,tsx}": {
        condition: {
          all: [
            { not: "foreign" },  // Exclude node_modules
            "development",        // Only in development mode
          ],
        },
        loaders: [
          {
            loader: "macaly-tagger",
            options: {
              disableSourceMaps: true,  // Required to avoid Turbopack crashes
            },
          },
        ],
        as: "*",  // Preserve original file handling
      },
    },
  },
};

module.exports = nextConfig;
```

> **Important Notes for Turbopack:**
> - **`disableSourceMaps: true` is required** to prevent Turbopack crashes when processing source maps
> - **`as: "*"`** preserves the original file type handling (don't use `"*.js"`)
> - **Don't include `'browser'` condition** as it may exclude server components in Next.js
> - The simple `"*.{jsx,tsx}"` glob pattern works correctly with these settings

#### For Next.js with Webpack (legacy)

Configure your `next.config.js`:

```js
const path = require("path");

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config, { dev, isServer }) => {
    // Only apply in development
    if (dev) {
      config.module.rules.unshift({
        test: /\.(jsx|tsx)$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "macaly-tagger",
          },
        ],
        enforce: "pre", // Run before other loaders
      });
    }

    return config;
  },
};

module.exports = nextConfig;
```

### Webpack Setup

For custom webpack configurations:

```js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(jsx|tsx)$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "macaly-tagger",
          },
        ],
        enforce: "pre",
      },
      // ... other rules
    ],
  },
};
```

### Vite Setup

For Vite projects, you'll need a Vite plugin wrapper (not included in this package).

## Example

### Input JSX:

```jsx
export default function TestComponent() {
  return (
    <div className="container">
      <h1>Hello Macaly!</h1>
      <button onClick={() => console.log("clicked")}>Click me</button>
      <MyLib.SpecialButton />
    </div>
  );
}
```

### Output HTML (in browser):

```html
<div
  data-macaly-loc="components/TestComponent.jsx:3:4"
  data-macaly-name="div"
  class="container"
>
  <h1 data-macaly-loc="components/TestComponent.jsx:4:6" data-macaly-name="h1">
    Hello Macaly!
  </h1>
  <button
    data-macaly-loc="components/TestComponent.jsx:5:6"
    data-macaly-name="button"
  >
    Click me
  </button>
  <button
    data-macaly-loc="components/TestComponent.jsx:8:6"
    data-macaly-name="MyLib.SpecialButton"
  >
    Special
  </button>
</div>
```

## How It Works

The loader:

1. **Parses JSX/TSX files** using Babel parser
2. **Walks the AST** to find JSX opening elements
3. **Adds location attributes** with file path, line, and column information
4. **Preserves source maps** for debugging
5. **Skips already tagged elements** to avoid duplicates

## Configuration

The loader works out of the box with no configuration needed. It automatically:

- Processes only `.jsx` and `.tsx` files
- Excludes `node_modules` directory
- Runs only in development mode (when configured properly)
- Handles both regular JSX elements (`<div>`) and member expressions (`<MyLib.Button>`)

### Options

You can pass options to the loader:

```js
{
  loader: 'macaly-tagger',
  options: {
    debug: true,              // Enable debug logging
    disableSourceMaps: true,  // Disable source map generation (useful for Turbopack)
    ignorePackages: [         // Skip components imported from these packages
      '@react-three/fiber',
      '@react-three/drei',
    ],
  },
}
```

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `debug` | `boolean` | `false` | Enable detailed console logging for debugging |
| `disableSourceMaps` | `boolean` | `false` | Disable source map generation (recommended for Turbopack to avoid crashes) |
| `ignorePackages` | `string[]` | `[]` | List of package names whose imports should not be tagged |

### Custom Renderers (React Three Fiber, etc.)

If you're using custom React renderers like [React Three Fiber](https://github.com/pmndrs/react-three-fiber), you may encounter errors because these renderers use components that don't support DOM attributes.

Use the `ignorePackages` option to skip tagging components imported from these packages:

```js
{
  loader: 'macaly-tagger',
  options: {
    ignorePackages: [
      '@react-three/fiber',
      '@react-three/drei',
      '@react-three/postprocessing',
      'three',
    ],
  },
}
```

This will automatically skip tagging any component imported from these packages:

```jsx
import { Canvas } from '@react-three/fiber';           // Canvas will NOT be tagged
import { OrbitControls, Html } from '@react-three/drei'; // OrbitControls, Html will NOT be tagged
import * as Fiber from '@react-three/fiber';           // Fiber.* will NOT be tagged

function Scene() {
  return (
    <div>                    {/* ✓ Tagged (HTML element) */}
      <Canvas>               {/* ✗ Skipped (imported from @react-three/fiber) */}
        <OrbitControls />    {/* ✗ Skipped (imported from @react-three/drei) */}
        <Html>               {/* ✗ Skipped (imported from @react-three/drei) */}
          <span>Label</span> {/* ✓ Tagged (HTML element) */}
        </Html>
        <mesh>               {/* ✗ Skipped (lowercase non-HTML element) */}
          <boxGeometry />    {/* ✗ Skipped (lowercase non-HTML element) */}
        </mesh>
      </Canvas>
    </div>
  );
}
```

The loader handles all import styles:
- **Named imports**: `import { Canvas } from '...'`
- **Default imports**: `import Drei from '...'` (skips `Drei.Something`)
- **Namespace imports**: `import * as Fiber from '...'` (skips `Fiber.Something`)

## Attributes Added

For each JSX element, the loader adds:

- `data-macaly-loc`: File path, line, and column (e.g., `"components/Button.jsx:15:8"`)
- `data-macaly-name`: Component/element name (e.g., `"button"` or `"MyLib.Button"`)

## Browser DevTools Integration

Once installed, you can:

1. Open browser DevTools
2. Inspect any element
3. See the `data-macaly-loc` attribute to find the exact source location
4. Use browser extensions or custom scripts to jump to source code

## Troubleshooting

### Not seeing attributes?

1. **Check console for errors**: Look for `[macaly-tagger]` warnings in the browser console
2. **Verify development mode**: Ensure the loader only runs in development (`dev && !isServer` for Next.js)
3. **Check file extensions**: Only `.jsx` and `.tsx` files are processed

### Build errors?

1. **Install dependencies**: Ensure all peer dependencies are installed
2. **Check webpack version**: Requires webpack >= 4.0.0 (for webpack setup)
3. **Verify loader path**: Make sure the loader is correctly referenced

### Performance issues?

The loader is optimized for development:

- Only processes JSX/TSX files
- Excludes node_modules automatically
- Uses efficient AST walking
- Includes source map support

### Enable debug logging

Add a console log to see which files are being processed:

```js
// In your webpack config
{
  loader: 'macaly-tagger',
  options: {
    debug: true // If you implement options support
  }
}
```

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. Submit a pull request

## License

MIT License - see LICENSE file for details.

## Changelog

### 1.2.0

- Added `ignorePackages` option to skip tagging components imported from specified packages
- Added automatic filtering for React Fragments (`<Fragment>`, `<React.Fragment>`)
- Added smart element filtering: only tags HTML/SVG elements and React components, skips unknown lowercase elements (custom renderer elements like R3F's `<mesh>`, `<boxGeometry>`, etc.)
- Improved compatibility with React Three Fiber and other custom renderers

### 1.1.0

- Added `disableSourceMaps` option to prevent Turbopack crashes
- Added comprehensive Turbopack configuration documentation
- Tested and verified Turbopack compatibility with Next.js 15.3.0+

### 1.0.0

- Initial release
- Support for JSX and TSX files
- Location tracking with file, line, and column
- Member expression support (e.g., `MyLib.Button`)
- Source map preservation
