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

@macaly/static-tagger

v0.1.0

Published

Vite plugin that injects source-location data attributes onto JSX elements at build time, so production HTML/JS carries data-macaly-loc / data-macaly-name pointing back at the original source coordinate.

Readme

@macaly/static-tagger

Vite plugin. Rewrites .jsx / .tsx source so every JSX element gains two static attributes:

  • data-macaly-loc="<relative/path.tsx>:<line>:<col>" — points back at the source coordinate where the element was authored.
  • data-macaly-name="<TagName>"div, Button, MyLib.Card, …

The rewrite happens before JSX is lowered to _jsx() / React.createElement(), so the attributes survive into the bundled JS as ordinary string props on regular HTML elements. They land in:

  • the production DOM for SPA builds (after React mounts client-side);
  • the prerendered HTML for SSG/SSR builds (TanStack Start, Vike, Astro React islands, Remix/React Router SSR, etc.) — visible without JS.

Intended use: click an element in the browser → jump to the exact source line in your editor. This package only writes the attributes; a separate runtime/extension reads them.

Vite-only. Build-time only. No webpack, no Turbopack, no dev-server tagging.

Installation

npm install --save-dev @macaly/static-tagger
# or: pnpm add -D @macaly/static-tagger

Usage

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { macalyTagger } from '@macaly/static-tagger';

export default defineConfig({
  plugins: [
    macalyTagger({
      // ignorePackages: ['@react-three/fiber', '@react-three/drei'],
      // disableSourceMaps: false,
      // debug: false,
    }),
    react(),
  ],
});

macalyTagger() must come before @vitejs/plugin-react. The plugin sets enforce: 'pre' so Vite always runs it before non-pre plugins, but keeping it first in the array is the obvious form.

How it works

your src/Foo.tsx                            <Foo data-macaly-loc=... data-macaly-name=...>
   ↓                                                     ↑
[macalyTagger plugin]   parse → walk AST → magic-string  │
   ↓ injects 2 string attrs onto each JSXOpeningElement  │
                                                         │
[@vitejs/plugin-react]  JSX → _jsx("Foo", { ... })       │
   ↓ attrs become regular string-valued object props     │
                                                         │
[esbuild / rollup]      bundle, tree-shake, minify       │
   ↓                                                     │
dist/assets/*.js        contains data-macaly-loc="…"  ───┘
   ↓
SPA: browser loads → React mounts → DOM has the attrs
SSG/SSR: prerender writes them straight into dist/**/*.html

Mechanics:

  1. enforce: 'pre' — Vite's transform pipeline runs pre plugins before user plugins. @vitejs/plugin-react is a user plugin, so we get the file while JSXOpeningElement nodes still exist. After plugin-react has run, JSX is lowered to _jsx(...) calls and there is nothing tag-shaped left to rewrite.
  2. apply: 'build' — only runs during vite build. The dev server is left untouched. (Dev-mode tagging is out of scope.)
  3. AST rewrite, not codegen — parses with @babel/parser (jsx+typescript plugins), walks with estree-walker, splices two attributes after the tag name with magic-string. The rest of the source is byte-identical, including indentation, comments, and trailing commas. A high-resolution sourcemap is returned alongside the code.
  4. What ends up in the bundle — for a host element:
    <button onClick={...}>Click</button>
    the plugin produces:
    <button data-macaly-loc="src/App.tsx:42:8" data-macaly-name="button" onClick={...}>Click</button>
    plugin-react/esbuild lowers that to:
    _jsx("button", { "data-macaly-loc": "src/App.tsx:42:8", "data-macaly-name": "button", onClick: ..., children: "Click" })
    At render time React forwards both data-* props to the DOM, exactly as it would for any other prop.
  5. Skipped automatically — virtual modules (ids starting with \0), files outside .jsx/.tsx, anything under node_modules, React Fragments, lowercase non-HTML/SVG tags (custom-renderer elements like R3F's <mesh>, <boxGeometry>), and any element already carrying data-macaly-loc. Components imported from packages listed in ignorePackages are also skipped — see below.

SPA vs SSG/SSR

Plugin behavior is identical. The difference is where the attributes become visible:

  • SPA (vite build with default index.html): dist/index.html is an empty shell. Attributes appear in the DOM only after React mounts. View via DevTools → Elements.
  • SSG / SSR (TanStack Start, Vike, Astro React islands, Remix/React Router SSR, etc.): the prerenderer runs your components on the server, React's HTML serializer emits the data-macaly-* attributes into the markup, and they sit directly in the static .html output — visible without JavaScript.

No configuration changes between the two modes.

Options

macalyTagger({
  debug: false,             // verbose console logging
  disableSourceMaps: false, // skip generating the high-res sourcemap
  ignorePackages: [],       // see "Custom renderers" section
});

| Option | Type | Default | Description | |--------|------|---------|-------------| | debug | boolean | false | Log each file processed and each tag decision. | | disableSourceMaps | boolean | false | Don't return a sourcemap from the transform. | | ignorePackages | string[] | [] | Don't tag components imported from these packages. |

Programmatic API

import { transformJSX } from '@macaly/static-tagger';

const result = transformJSX(sourceCode, '/abs/path/src/App.tsx', '/abs/path', {
  ignorePackages: ['@react-three/fiber'],
});
// result === null  → file skipped or no taggable JSX
// result === { code, map }

transformJSX is the framework-agnostic core; the Vite plugin is a thin shell around it.

Example

Input:

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

After build, in the rendered DOM (or prerendered HTML):

<div data-macaly-loc="components/TestComponent.tsx:3:4" data-macaly-name="div" class="container">
  <h1 data-macaly-loc="components/TestComponent.tsx:4:6" data-macaly-name="h1">Hello Macaly!</h1>
  <button data-macaly-loc="components/TestComponent.tsx:5:6" data-macaly-name="button">Click me</button>
  <!-- MyLib.SpecialButton renders whatever it renders, with data-macaly-* forwarded onto its root -->
</div>

Custom renderers (React Three Fiber, etc.)

Renderers that map JSX onto non-DOM hosts (R3F's <mesh>, <boxGeometry>, …) cannot accept data-* props. Two layers of filtering keep them clean:

  1. Heuristic — lowercase tag names that aren't standard HTML/SVG are never tagged. R3F's <mesh>, <boxGeometry>, <meshStandardMaterial>, <ambientLight>, etc. fall out automatically.
  2. ignorePackages — for capitalized React components from these renderers (e.g. <Canvas> from @react-three/fiber, <OrbitControls> from @react-three/drei), list the package and the plugin skips every component imported from it.
macalyTagger({
  ignorePackages: [
    '@react-three/fiber',
    '@react-three/drei',
    '@react-three/postprocessing',
    'three',
  ],
});
import { Canvas } from '@react-three/fiber';            // Canvas → skipped
import { OrbitControls, Html } from '@react-three/drei'; // skipped
import * as Fiber from '@react-three/fiber';            // Fiber.* → skipped

function Scene() {
  return (
    <div>                    {/* tagged */}
      <Canvas>               {/* skipped (imported from ignored pkg) */}
        <OrbitControls />    {/* skipped */}
        <Html>               {/* skipped */}
          <span>Label</span> {/* tagged (HTML element) */}
        </Html>
        <mesh>               {/* skipped (lowercase non-HTML) */}
          <boxGeometry />    {/* skipped */}
        </mesh>
      </Canvas>
    </div>
  );
}

All three import styles are handled:

  • import { Canvas } from '...' (named) → Canvas is skipped.
  • import Drei from '...' (default) → Drei.* is skipped.
  • import * as Fiber from '...' (namespace) → Fiber.* is skipped.

Troubleshooting

No data-macaly-* in the DOM. Confirm macalyTagger() is listed before @vitejs/plugin-react. If plugin-react sees the file first, JSX has already been lowered and there's nothing to rewrite.

Plugin doesn't run during vite dev. By design — apply: 'build'. Tagging is a build-time-only feature.

Element type is invalid from a custom renderer. That renderer doesn't accept data-* props. Add its package to ignorePackages.

Loud logging? Set debug: true.

License

MIT — see LICENSE.