CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-devtools-experimental

Experimental rewrite of React DevTools extension for debugging React applications with improved performance and multi-root support

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

frontend-store.mddocs/

Frontend Store

The Frontend Store is the central state management system for the DevTools UI that maintains the element tree, handles bridge communication, manages profiling data, and provides event-driven updates to React components.

Capabilities

Store Class

Central state management class that extends EventEmitter for the DevTools frontend.

/**
 * Central state management for DevTools frontend
 * Manages element tree, profiling data, and bridge communication
 */
class Store extends EventEmitter {
  /**
   * Create a new store instance
   * @param bridge - Bridge for backend communication
   * @param config - Optional configuration settings
   */
  constructor(bridge: Bridge, config?: Config);
  
  /** Current profiling cache instance */
  get profilingCache(): ProfilingCache;
  
  /** Number of elements in the tree */
  get numElements(): number;
  
  /** Current tree revision number */
  get revision(): number;
  
  /** Array of root element IDs */
  get roots(): $ReadOnlyArray<number>;
  
  /** Whether profiling is supported */  
  get supportsProfiling(): boolean;
  
  /** Whether reload and profile is supported */
  get supportsReloadAndProfile(): boolean;
  
  /** Whether profiling is currently active */
  get isProfiling(): boolean;
  
  /** Whether profiling data is available */
  get hasProfilingData(): boolean;
}

interface Config {
  /** Enable reload and profile functionality */
  supportsReloadAndProfile?: boolean;
  /** Enable profiling functionality */
  supportsProfiling?: boolean;
}

Usage Examples:

import Store from "react-devtools-experimental/src/devtools/store";
import Bridge from "react-devtools-experimental/src/bridge";

// Create store with profiling support
const config = {
  supportsProfiling: true,
  supportsReloadAndProfile: true
};

const store = new Store(bridge, config);

// Listen for store updates
store.on('tree-updated', () => {
  console.log(`Tree updated, ${store.numElements} elements`);
});

// Check profiling status
if (store.supportsProfiling) {
  console.log(`Profiling active: ${store.isProfiling}`);
  console.log(`Has profiling data: ${store.hasProfilingData}`);
}

Element Access Methods

Methods for accessing and querying elements in the DevTools tree.

/**
 * Get element at specific index in the flattened tree
 * @param index - Zero-based index in the tree
 * @returns Element data or null if not found
 */
getElementAtIndex(index: number): Element | null;

/**
 * Get element ID at specific index
 * @param index - Zero-based index in the tree
 * @returns Element ID or null if not found
 */
getElementIDAtIndex(index: number): number | null;

/**
 * Get element by its unique ID
 * @param id - Element ID to look up
 * @returns Element data or null if not found
 */
getElementByID(id: number): Element | null;

/**
 * Get index of element with specific ID
 * @param id - Element ID to find index for
 * @returns Index in tree or null if not found
 */
getIndexOfElementID(id: number): number | null;

Usage Examples:

// Access elements by index
const firstElement = store.getElementAtIndex(0);
console.log('First element:', firstElement);

// Find element by ID
const elementID = 42;
const element = store.getElementByID(elementID);
if (element) {
  console.log(`Element ${elementID}:`, element.displayName);
}

// Get element index for scrolling
const elementIndex = store.getIndexOfElementID(elementID);
if (elementIndex !== null) {
  scrollToIndex(elementIndex);
}

// Iterate through all elements
for (let i = 0; i < store.numElements; i++) {
  const element = store.getElementAtIndex(i);
  if (element) {
    console.log(`${element.displayName} (depth: ${element.depth})`);
  }
}

Renderer Information

Methods for getting information about renderers and roots.

/**
 * Get renderer ID for a specific element
 * @param id - Element ID
 * @returns Renderer ID or null if not found
 */
getRendererIDForElement(id: number): number | null;

/**
 * Get root ID for a specific element
 * @param id - Element ID  
 * @returns Root ID or null if not found
 */
getRootIDForElement(id: number): number | null;

Usage Examples:

// Get renderer information for element
const elementID = 42;
const rendererID = store.getRendererIDForElement(elementID);
const rootID = store.getRootIDForElement(elementID);

console.log(`Element ${elementID}:`);
console.log(`  Renderer: ${rendererID}`);
console.log(`  Root: ${rootID}`);

// Use for backend operations
if (rendererID && rootID) {
  bridge.send('inspect-element', { 
    id: elementID, 
    rendererID: rendererID 
  });
}

Profiling Control

Methods for controlling performance profiling sessions.

/**
 * Start performance profiling session
 * Sends command to backend to begin collecting performance data
 */
startProfiling(): void;

/**
 * Stop performance profiling session
 * Sends command to backend to end data collection
 */
stopProfiling(): void;

Usage Examples:

// Start profiling session
if (store.supportsProfiling && !store.isProfiling) {
  store.startProfiling();
  console.log('Profiling started');
}

// Stop profiling session
if (store.isProfiling) {
  store.stopProfiling();
  console.log('Profiling stopped');
}

// Listen for profiling status changes
store.on('profiling-status-changed', (isProfiling) => {
  console.log(`Profiling ${isProfiling ? 'started' : 'stopped'}`);
  updateProfilingUI(isProfiling);
});

Event Handling

Key events emitted by the store for UI updates and data synchronization.

// Core store events
'tree-updated'              // Element tree has changed
'element-selected'          // Element selection changed
'profiling-status-changed'  // Profiling status changed
'profiling-data-available'  // New profiling data received
'bridge-connected'          // Backend bridge connected
'bridge-disconnected'       // Backend bridge disconnected
'store-reset'              // Store state reset

Usage Examples:

// Listen for tree updates
store.on('tree-updated', () => {
  // Re-render tree UI
  updateElementTree();
});

// Listen for element selection
store.on('element-selected', (elementID) => {
  // Update selection UI
  highlightSelectedElement(elementID);
  
  // Load element details
  loadElementInspection(elementID);
});

// Listen for profiling data
store.on('profiling-data-available', () => {
  // Update profiler UI
  if (store.hasProfilingData) {
    showProfilingResults();
  }
});

// Handle bridge disconnection
store.on('bridge-disconnected', () => {
  showDisconnectedState();
});

Bridge Operations Handling

Internal methods for processing bridge messages and operations.

/**
 * Handle operations from bridge
 * Internal method that processes tree operations from backend
 * @param operations - Serialized operations data
 */
onBridgeOperations(operations: Uint32Array): void;

/**
 * Handle profiling status updates
 * @param isProfiling - Current profiling status
 */
onProfilingStatus(isProfiling: boolean): void;

/**
 * Handle bridge shutdown
 * Cleans up resources when backend disconnects
 */
onBridgeShutdown(): void;

Debug Methods

Utility methods for debugging and development.

/**
 * Print element tree to console for debugging
 * Development/debug method to visualize tree structure
 */
__printTree(): void;

Usage Examples:

// Debug tree structure
if (process.env.NODE_ENV === 'development') {
  store.__printTree();
}

Element Data Structure

Element Interface

The primary data structure representing React elements in the DevTools tree.

interface Element {
  /** Unique element identifier */
  id: number;
  /** Parent element ID (0 for roots) */
  parentID: number;
  /** Array of child element IDs */
  children: Array<number>;
  /** Element type classification */
  type: ElementType;
  /** Display name for the element */
  displayName: string | null;
  /** React key prop */
  key: number | string | null;
  /** Owner element ID */
  ownerID: number;
  /** Nesting depth in tree */
  depth: number;
  /** Number of descendants */
  weight: number;
}

/** Element type constants */
const ElementTypeClass = 1;
const ElementTypeFunction = 2;
const ElementTypeContext = 3;
const ElementTypeForwardRef = 4;
const ElementTypeMemo = 5;
const ElementTypeOtherOrUnknown = 6;
const ElementTypeProfiler = 7;
const ElementTypeRoot = 8;
const ElementTypeSuspense = 9;

type ElementType = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;

Usage Examples:

// Process element based on type
const element = store.getElementByID(42);
if (element) {
  switch (element.type) {
    case ElementTypeClass:
      console.log(`Class component: ${element.displayName}`);
      break;
    case ElementTypeFunction:
      console.log(`Function component: ${element.displayName}`);
      break;
    case ElementTypeContext:
      console.log(`Context: ${element.displayName}`);
      break;
    default:
      console.log(`Other element: ${element.displayName}`);
  }
  
  // Access element hierarchy
  console.log(`Parent: ${element.parentID}`);
  console.log(`Children: ${element.children.length}`);
  console.log(`Depth: ${element.depth}`);
}

Store Integration Patterns

React Component Integration

Using the store with React components and hooks:

import { useContext, useEffect, useState } from 'react';
import { StoreContext } from 'react-devtools-experimental/src/devtools/views/context';

function ElementTree() {
  const store = useContext(StoreContext);
  const [revision, setRevision] = useState(store.revision);
  
  useEffect(() => {
    const handleTreeUpdate = () => {
      setRevision(store.revision);
    };
    
    store.on('tree-updated', handleTreeUpdate);
    return () => store.off('tree-updated', handleTreeUpdate);
  }, [store]);
  
  // Render tree based on current revision
  return (
    <div>
      {store.roots.map(rootID => (
        <ElementNode key={rootID} elementID={rootID} store={store} />
      ))}
    </div>
  );
}

Suspense Integration with Profiling Cache

The store integrates with React Suspense for async profiling data:

import { Suspense } from 'react';

function ProfilingResults() {
  const store = useContext(StoreContext);
  
  if (!store.hasProfilingData) {
    return <div>No profiling data available</div>;
  }
  
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <ProfilingDataDisplay cache={store.profilingCache} />
    </Suspense>
  );
}

function ProfilingDataDisplay({ cache }) {
  // This will suspend if data is not ready
  const profilingData = cache.read();
  
  return (
    <div>
      <h3>Profiling Results</h3>
      <ProfilingChart data={profilingData} />
    </div>
  );
}

Store Lifecycle Management

Proper setup and cleanup of the store:

function createDevToolsStore(bridge, config) {
  const store = new Store(bridge, config);
  
  // Set up error handling
  store.on('error', (error) => {
    console.error('Store error:', error);
  });
  
  // Set up cleanup
  const cleanup = () => {
    store.removeAllListeners();
    store.onBridgeShutdown();
  };
  
  // Cleanup on page unload
  window.addEventListener('beforeunload', cleanup);
  
  return { store, cleanup };
}

// Usage
const { store, cleanup } = createDevToolsStore(bridge, config);

// Later cleanup
cleanup();

docs

backend-agent.md

bridge-communication.md

data-hydration.md

devtools-ui.md

frontend-store.md

hook-system.md

index.md

performance-profiling.md

tile.json