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

vue-why-did-you-render

v1.2.0

Published

Debug Vue render performance - see why your components are re-rendering

Readme

vue-why-did-you-render 🔍

Commitizen friendly

Debug Vue 3 render performance issues. See exactly why your components re-render.

Inspired by React's why-did-you-render, but designed for Vue 3's reactivity system.

Features

  • Track render causes - See which reactive dependency triggered a re-render
  • Detect no-op renders - Identify renders where values don't actually change
  • Group by source - Understand if changes came from props, refs, computed, or store
  • Zero production overhead - Disabled in production builds
  • TypeScript support - Full type definitions included
  • Vue 3 native - Built for the Composition API

Installation

npm install vue-why-did-you-render

Quick Start

import { createApp } from "vue";
import { enableWhyDidYouRender } from "vue-why-did-you-render";
import App from "./App.vue";

const app = createApp(App);

// Enable in development only
if (import.meta.env.DEV) {
  enableWhyDidYouRender(app, {
    logOnConsole: true,
    logLevel: "warn",
  });
}

app.mount("#app");

Console Output

When a component mounts:

✅ [UserCard] Mounted
  Triggers:
    ✅ [ref:set] "isOpen" (undefined → false)

When a component re-renders:

✅ [UserCard] (render #2) Re-rendered
  Triggers:
    ✅ [ref:set] "isOpen" (false → true)
  Source breakdown: ref(1)

For unnecessary renders (values unchanged):

⚠️  [Dashboard] (render #3) Re-rendered
  Triggers:
    ❌ [reactive:set] "count" (5 → 5) (UNCHANGED!)
  ⚠️  Found 1 unnecessary trigger (values unchanged)

API

enableWhyDidYouRender(app, options)

Initialize the debugging library.

Parameters:

  • app - Vue application instance
  • options - Configuration options

Returns: WhyDidYouRenderInstance with control methods

Options

interface WhyDidYouRenderOptions {
  // Component filtering
  include?: (string | RegExp)[]; // Only track these components
  exclude?: (string | RegExp)[]; // Skip these components

  // Logging
  logLevel?: "verbose" | "warn" | "error"; // Default: 'warn'
  logOnConsole?: boolean; // Default: true
  maxDepth?: number; // Default: 3
  maxStringLength?: number; // Default: 100

  // Behavior
  pauseOnInit?: boolean; // Default: false
  groupUpdates?: boolean; // Default: false
  throttleMs?: number; // Debounce rapid renders

  // Integration
  onRender?: (event) => void; // Custom callback
  enablePiniaTracking?: boolean; // Default: false
  enableDevtools?: boolean; // Default: false (coming soon)
  collectStackTrace?: boolean; // Default: false
}

Instance Methods

interface WhyDidYouRenderInstance {
  pause(); // Stop logging
  resume(); // Resume logging
  reset(); // Clear history
  getStats(): RenderStats; // Get statistics
  configure(options: Partial<Options>); // Update configuration
}

Examples

Basic Usage

enableWhyDidYouRender(app, {
  logOnConsole: true,
});

Track Specific Components

enableWhyDidYouRender(app, {
  include: [/UserCard/, /Dashboard/, "Header"],
  logOnConsole: true,
});

Exclude Components

enableWhyDidYouRender(app, {
  exclude: [/Tooltip/, "Loading"],
  logOnConsole: true,
});

Custom Log Level

enableWhyDidYouRender(app, {
  logLevel: "verbose", // Log everything
  logOnConsole: true,
});

Control at Runtime

const tracker = enableWhyDidYouRender(app, {
  logOnConsole: true,
});

// Later: pause/resume as needed
tracker.pause(); // Stop logging
tracker.resume(); // Resume logging
tracker.reset(); // Clear history

Custom Callback

enableWhyDidYouRender(app, {
  logOnConsole: false,
  onRender: (event) => {
    // Send to analytics, monitoring service, etc.
    console.log(`${event.componentName} rendered ${event.triggers.length} times`);
  },
});

Pinia Store Tracking

import { createPinia } from 'pinia'
import { enableWhyDidYouRender } from 'vue-why-did-you-render'

const app = createApp(App)
const pinia = createPinia()

app.use(pinia)

// Enable with Pinia tracking
const { registerStore } = enableWhyDidYouRender(app, {
  logOnConsole: true,
  enablePiniaTracking: true,
})

// Register stores you want to track
import { useMyStore } from './stores/myStore'
const myStore = useMyStore()
registerStore(myStore)

Console output for Pinia stores:

✅ [MyComponent] Re-rendered
  Triggers:
    ✅ [store:myStore] (state) "loading" (false → true)
    ✅ [store:myStore] (getter) "filteredItems" (Array(5) → Array(3))
  Source breakdown: store(2)

How It Works

The library hooks into Vue 3's internal reactivity system using:

  • onRenderTracked - Captures which dependencies are accessed during render
  • onRenderTriggered - Captures what caused the re-render to happen
  • onUpdated - Finalizes the event after DOM update completes

Then it:

  1. Maps each dependency change to its component
  2. Detects no-op renders (old value === new value)
  3. Classifies triggers by source (ref, computed, prop, store)
  4. Formats output with helpful emoji indicators
  5. Logs to console or calls custom callback

Understanding Output

Badges

  • Green check - Expected render (value changed)
  • ⚠️ Yellow warning - Suspicious (unchanged values or multiple sources)
  • Red X - Unnecessary render (value unchanged)

Source Types

  • ref:set - Ref value assignment
  • reactive:set - Reactive object mutation
  • computed - Computed property dependency
  • prop - Props passed from parent
  • store - Pinia store mutation

Trigger Types

  • set - Value assignment
  • add - Array/object property added
  • delete - Array/object property deleted
  • clear - Collection cleared

Performance Considerations

The library is designed to have minimal overhead:

  • ✅ Disabled in production (NODE_ENV !== 'development')
  • ✅ Optional component filtering (include/exclude)
  • ✅ Shallow object inspection by default
  • ✅ String truncation to prevent huge logs
  • ✅ Can be paused at runtime

Use include to track only specific components in large apps.

Best Practices

  1. Limit tracked components

    enableWhyDidYouRender(app, {
      include: [/Page/, /Card/, /List/], // Only track these
    });
  2. Use warn level (not verbose by default)

    enableWhyDidYouRender(app, {
      logLevel: "warn", // Only show important renders
    });
  3. Check for unchanged values - These are performance issues

    ❌ [store:myStore] (getter) "count" (5 → 5) (UNCHANGED!)
    → This means unnecessary rendering is happening
  4. Pause during testing to reduce noise

    const tracker = enableWhyDidYouRender(app);
    tracker.pause(); // In test setup

Troubleshooting

No logs appearing?

  1. Check that you're in development mode (import.meta.env.DEV)
  2. Verify logOnConsole: true is set
  3. Check that components match include filter (if specified)
  4. Open browser DevTools Console tab

Logs too verbose?

// Use 'warn' instead of 'verbose'
enableWhyDidYouRender(app, {
  logLevel: "warn",
});

// Or track only specific components
enableWhyDidYouRender(app, {
  include: [/ImportantComponent/],
});

Performance impact?

// Disable in production (already does this automatically)
if (import.meta.env.DEV) {
  enableWhyDidYouRender(app);
}

// Or pause when not needed
tracker.pause();

Roadmap

  • [x] Pinia store mutation tracking
  • [ ] Vue Devtools panel integration
  • [ ] Performance timeline visualization
  • [ ] Render comparison between commits
  • [ ] Custom formatters and plugins
  • [ ] Export/import render traces

Development

# Install dependencies
pnpm install

# Build the library
pnpm run build

# Run tests
pnpm run test

# Type checking
pnpm run typecheck

# Linting
pnpm run lint
pnpm run lint:fix  # Auto-fix issues

# Formatting
pnpm run format
pnpm run format:check

# Run all checks (typecheck + lint + format)
pnpm run check

# Run the demo app
cd examples/demo
pnpm install
pnpm run dev

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run pnpm run check to ensure code quality
  5. Run pnpm run test to ensure tests pass
  6. Commit your changes using Commitizen:
    git add -A
    pnpm commit
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

Committing Changes

We use Conventional Commits for all commits. Commitizen helps build and enforce commit messages.

# Stage your changes
git add -A

# Use Commitizen to create your commit
pnpm commit

This will trigger an interactive prompt to help compose your commit message.

License

MIT © 2025

Related Projects