react-devtools-metadata
v1.1.0
Published
Comprehensive React component metadata injection with performance tracking, source location, props, and more
Maintainers
Readme
React DevTools Metadata
🚀 Zero-config metadata injection for React components - Just add the plugin and go!
✨ Zero Configuration
No imports. No setup code. Just add the plugin.
npm install --save-dev react-devtools-metadata// vite.config.js
import reactMetadata from 'react-devtools-metadata/vite'
export default defineConfig({
plugins: [react(), reactMetadata()]
})That's it! Everything works automatically.
Features
- ✅ Zero Configuration - Just add the plugin
- ✅ Absolute File Paths - No manual project root setup
- ✅ Exact Line & Column Numbers - Pinpoint accuracy
- ✅ Performance Metrics - Automatic render time tracking
- ✅ Props Inspection - Runtime props available
- ✅ Git Integration - Optional commit information (enable with
git: true) - ✅ Multiple Bundlers - Babel, Vite, Webpack support
- ✅ Zero Production Overhead - Automatically disabled in production
Installation
npm install --save-dev react-devtools-metadataQuick Start
Vite
// vite.config.js
import react from '@vitejs/plugin-react';
import reactMetadata from 'react-devtools-metadata/vite';
export default defineConfig({
plugins: [
react(),
reactMetadata() // ✅ That's it!
]
});Optional configuration:
reactMetadata({
performance: true, // Track render performance (default: true)
debug: false, // Log transformation details (default: false)
git: false // Include git blame info (default: false, slower)
})Webpack / Create React App
// babel.config.js
module.exports = {
presets: ['@babel/preset-react'],
env: {
development: {
plugins: ['react-devtools-metadata/babel'] // ✅ That's it!
}
}
};Optional configuration:
plugins: [
['react-devtools-metadata/babel', {
performance: true, // Track performance (default: true)
debug: false, // Log details (default: false)
git: false // Include git info (default: false)
}]
]Next.js
// next.config.js
module.exports = {
webpack: (config, { dev, isServer }) => {
if (dev && !isServer) {
config.module.rules.push({
test: /\.(jsx|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
plugins: [['react-devtools-metadata/babel', { performance: true }]]
}
}
});
}
return config;
}
};What You Get
Before
// Limited React internal data
{
componentName: "MyComponent",
fileName: "Unknown"
}After
// Complete metadata + performance tracking
{
componentName: "MyComponent",
displayName: "MyComponent",
fileName: "MyComponent.jsx",
filePath: "src/components/MyComponent.jsx",
absolutePath: "/Users/you/project/src/components/MyComponent.jsx",
lineNumber: 15,
columnNumber: 0,
// Performance metrics
performance: {
renderCount: 5,
totalRenderTime: 45.2,
averageRenderTime: 9.04,
lastRenderTime: 8.5,
slowRenderWarnings: 0,
firstRenderAt: 1701234567890,
lastRenderAt: 1701234568123
},
// Props (runtime)
props: {
title: "Hello World",
count: 42,
onClick: "[Function]"
},
// Git info (optional)
git: {
lastCommit: "abc123",
lastAuthor: "John Doe",
lastModified: "2024-01-15"
}
}Browser Extension Integration
// In your Chrome extension's content script
function extractComponentMetadata(fiber) {
const component = fiber.type;
// Get injected metadata
const metadata = component?.__devMetadata;
if (metadata) {
console.log('Component:', metadata.componentName);
console.log('File:', metadata.absolutePath);
console.log('Line:', metadata.lineNumber);
console.log('Renders:', metadata.performance.renderCount);
console.log('Avg Time:', metadata.performance.averageRenderTime + 'ms');
}
// Get runtime props from fiber
const props = extractProps(fiber.memoizedProps);
return { ...metadata, props };
}Runtime Performance Tracking
The library automatically tracks component performance:
// Access performance data
const component = MyComponent;
const perf = component.__devMetadata.performance;
console.log(`Rendered ${perf.renderCount} times`);
console.log(`Average: ${perf.averageRenderTime}ms`);
console.log(`Last render: ${perf.lastRenderTime}ms`);
// Check for slow renders (>16ms)
if (perf.slowRenderWarnings > 0) {
console.warn(`⚠️ ${perf.slowRenderWarnings} slow renders detected!`);
}Configuration Options
Vite Plugin Options
interface VitePluginOptions {
// Enable/disable the plugin (default: process.env.NODE_ENV === 'development')
enabled?: boolean;
// Track performance metrics
performance?: boolean;
// Include git blame information (slower, requires git)
git?: boolean;
// Use source maps for original locations
sourceMaps?: boolean;
// Include file patterns (default: /\.(jsx|tsx)$/)
include?: RegExp | RegExp[];
// Exclude file patterns (default: /node_modules/)
exclude?: RegExp | RegExp[];
// Custom metadata extractor
customMetadata?: (filepath: string) => Record<string, any>;
}Babel Plugin Options
interface BabelPluginOptions {
// Track performance metrics
performance?: boolean;
// Include git information
git?: boolean;
// Use source maps
sourceMaps?: boolean;
// Project root (default: process.cwd())
projectRoot?: string;
// Custom metadata
customMetadata?: (filepath: string, state: any) => Record<string, any>;
}Performance Impact
Build Time
- Babel plugin: +5-10% build time
- Vite plugin: +2-5% build time (minimal)
Runtime
- Development: Negligible (<1ms per component mount)
- Production: Zero (plugin disabled)
Bundle Size
- Development: +2-5KB per component (metadata only)
- Production: 0KB (stripped by bundler)
Advanced Features
Custom Metadata
Add your own metadata to components:
// vite.config.js
reactMetadata({
customMetadata: (filepath) => ({
team: filepath.includes('/team-a/') ? 'Team A' : 'Team B',
feature: extractFeatureFromPath(filepath),
lastModified: fs.statSync(filepath).mtime
})
})Integration with React DevTools
// Expose to React DevTools
if (typeof window !== 'undefined') {
window.__REACT_DEVTOOLS_METADATA__ = {
getComponentMetadata: (fiber) => fiber.type?.__devMetadata,
getAllComponents: () => {
// Scan fiber tree and collect all metadata
}
};
}Performance Monitoring Dashboard
// Create a performance dashboard
function PerformanceDashboard() {
const [components, setComponents] = useState([]);
useEffect(() => {
// Collect all component metadata
const metadata = collectAllComponentMetadata();
// Sort by render count or average time
const sorted = metadata.sort((a, b) =>
b.performance.renderCount - a.performance.renderCount
);
setComponents(sorted);
}, []);
return (
<div>
{components.map(comp => (
<div key={comp.componentName}>
<h3>{comp.componentName}</h3>
<p>Renders: {comp.performance.renderCount}</p>
<p>Avg Time: {comp.performance.averageRenderTime}ms</p>
</div>
))}
</div>
);
}TypeScript Support
Full TypeScript support with type definitions:
import type { ComponentMetadata, PerformanceMetrics } from 'react-devtools-metadata/runtime';
function inspectComponent(fiber: any): ComponentMetadata | null {
return fiber.type?.__devMetadata || null;
}Debugging
Enable debug logging:
// vite.config.js
reactMetadata({
debug: true // Logs metadata injection details
})Troubleshooting
Metadata not showing up?
Check environment: Plugin only runs in development
console.log(process.env.NODE_ENV); // Should be 'development'Verify plugin is loaded:
// Should see plugin output in build logs npm run dev -- --debugCheck component detection:
// Component names must start with uppercase function MyComponent() {} // ✅ Works function myComponent() {} // ❌ Not detected
Performance tracking not working?
Ensure performance: true is set in plugin options:
reactMetadata({ performance: true })Source maps not resolving?
- Enable source maps in your bundler config
- Set
sourceMaps: truein plugin options - Check that
.mapfiles are generated
Examples
See the /examples directory for complete working examples:
API Reference
Runtime API
// Get metadata from component
function getComponentMetadata(component: React.ComponentType): ComponentMetadata | null;
// Get metadata from fiber
function getMetadataFromFiber(fiber: Fiber): ComponentMetadata | null;
// Extract safe props
function extractSafeProps(props: any): Record<string, any>;
// Performance tracking
function trackRender(componentName: string, renderTime: number): void;
function getPerformanceMetrics(componentName: string): PerformanceMetrics | null;Types
interface ComponentMetadata {
componentName: string;
displayName?: string;
fileName: string;
filePath: string;
absolutePath: string;
lineNumber: number;
columnNumber: number;
performance?: PerformanceMetrics;
props?: Record<string, any>;
git?: GitInfo;
timestamp: number;
}
interface PerformanceMetrics {
renderCount: number;
totalRenderTime: number;
averageRenderTime: number;
lastRenderTime: number;
slowRenderWarnings: number;
firstRenderAt: number;
lastRenderAt: number;
}
interface GitInfo {
lastCommit: string;
lastAuthor: string;
lastModified: string;
branch?: string;
}Contributing
Contributions are welcome! Please read CONTRIBUTING.md for details.
License
MIT © [Your Name]
Changelog
See CHANGELOG.md for release history.
