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

bridge-communication.mddocs/

Bridge Communication

The bridge communication system provides efficient message passing between different DevTools contexts (extension background, content script, injected script) with automatic message batching and event-driven architecture.

Capabilities

Bridge Class

Main communication bridge that extends EventEmitter for bidirectional message passing with automatic batching.

/**
 * Bridge for communication between DevTools contexts
 * Automatically batches messages for improved performance
 */
class Bridge extends EventEmitter {
  /**
   * Create a new bridge instance
   * @param wall - Low-level communication wall implementation
   */
  constructor(wall: Wall);
  
  /**
   * Send a message through the bridge with optional transferable objects
   * Messages are automatically batched for performance
   * @param event - Event name/type
   * @param payload - Data to send
   * @param transferable - Optional transferable objects for performance
   */
  send(event: string, payload: any, transferable?: Array<any>): void;
}

Usage Examples:

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

// Create wall implementation for your context
const wall = {
  listen: (callback) => {
    // Set up message listener (e.g., chrome.runtime.onMessage)
    chrome.runtime.onMessage.addListener(callback);
  },
  send: (event, payload, transferable) => {
    // Send message (e.g., chrome.runtime.sendMessage)
    chrome.runtime.sendMessage({ event, payload });
  }
};

// Create bridge
const bridge = new Bridge(wall);

// Listen for events
bridge.on('element-selected', (data) => {
  console.log('Element selected:', data);
});

// Send events
bridge.send('inspect-element', { id: 123, rendererID: 1 });

Wall Interface

Low-level communication abstraction that bridges must implement for their specific context.

interface Wall {
  /**
   * Set up listener for incoming messages
   * @param fn - Callback function to handle messages
   */
  listen: (fn: Function) => void;
  
  /**
   * Send message through the wall
   * @param event - Event name/type
   * @param payload - Data to send
   * @param transferable - Optional transferable objects
   */
  send: (event: string, payload: any, transferable?: Array<any>) => void;
}

Message Batching

The bridge automatically batches messages within a time window to reduce communication overhead.

/**
 * Message batching configuration
 */
const BATCH_DURATION = 100; // milliseconds

/**
 * Internal message structure
 */
interface Message {
  event: string;
  payload: any;
}

Usage Examples:

// Messages sent within 100ms are automatically batched
bridge.send('tree-operation', { type: 'ADD', id: 1 });
bridge.send('tree-operation', { type: 'ADD', id: 2 });
bridge.send('tree-operation', { type: 'ADD', id: 3 });
// All three messages sent as single batched message

// Batching can be bypassed for urgent messages by waiting
bridge.send('urgent-message', { critical: true });
await new Promise(resolve => setTimeout(resolve, 101));
bridge.send('another-message', { data: 'test' });

Wall Implementations

Chrome Extension Wall

Implementation for Chrome extension communication between background, content script, and injected contexts.

// Background script to content script
const backgroundWall = {
  listen: (callback) => {
    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
      callback(message);
    });
  },
  send: (event, payload) => {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      chrome.tabs.sendMessage(tabs[0].id, { event, payload });
    });
  }
};

// Content script to injected script
const contentWall = {
  listen: (callback) => {
    window.addEventListener('message', (event) => {
      if (event.source === window && event.data.source === 'react-devtools') {
        callback(event.data);
      }
    });
  },
  send: (event, payload) => {
    window.postMessage({
      source: 'react-devtools',
      event,
      payload
    }, '*');
  }
};

WebSocket Wall

Implementation for standalone DevTools using WebSocket communication.

const websocketWall = {
  listen: (callback) => {
    this.socket.on('message', (message) => {
      const data = JSON.parse(message);
      callback(data);
    });
  },
  send: (event, payload) => {
    this.socket.send(JSON.stringify({ event, payload }));
  }
};

Development Server Wall

Implementation for development environments with hot reloading.

const devServerWall = {
  listen: (callback) => {
    // Set up Server-Sent Events or WebSocket
    this.eventSource.onmessage = (event) => {
      const data = JSON.parse(event.data);
      callback(data);
    };
  },
  send: (event, payload) => {
    fetch('/devtools-message', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ event, payload })
    });
  }
};

Bridge Events

Core DevTools Events

Standard events used throughout the DevTools communication protocol.

// Element inspection events
'inspect-element'         // Request element inspection
'element-inspected'       // Element inspection result
'select-element'          // Select element in tree
'element-selected'        // Element selection result

// Tree operations
'tree-operations'         // Batch of tree changes
'tree-updated'           // Tree update notification

// Profiling events
'start-profiling'        // Start performance profiling
'stop-profiling'         // Stop performance profiling
'profiling-data'         // Profiling results

// State modification events
'override-props'         // Modify component props
'override-state'         // Modify component state
'override-context'       // Modify context values
'override-hooks'         // Modify hook state

// DOM inspection events
'start-dom-inspection'   // Enter DOM inspection mode
'stop-dom-inspection'    // Exit DOM inspection mode
'highlight-element'      // Highlight element in DOM
'unhighlight-element'    // Remove element highlighting

// Bridge lifecycle events
'bridge-ready'          // Bridge initialization complete
'bridge-shutdown'       // Bridge shutting down

Usage Examples:

// Set up comprehensive event handling
const bridge = new Bridge(wall);

// Element inspection
bridge.on('inspect-element', ({ id, rendererID }) => {
  const elementData = inspectElement(id, rendererID);
  bridge.send('element-inspected', elementData);
});

// Profiling control
bridge.on('start-profiling', () => {
  startProfilingSession();
  bridge.send('profiling-started', { timestamp: Date.now() });
});

bridge.on('stop-profiling', () => {
  const profilingData = stopProfilingSession();
  bridge.send('profiling-data', profilingData);
});

// State modification
bridge.on('override-props', ({ id, path, value, rendererID }) => {
  modifyComponentProps(id, path, value, rendererID);
  bridge.send('props-overridden', { id, path, value });
});

Error Handling

Bridge communication includes error handling and recovery mechanisms.

// Error events
'bridge-error'          // Communication error occurred
'message-failed'        // Specific message failed to send
'connection-lost'       // Connection to other context lost
'connection-restored'   // Connection restored

// Recovery events
'retry-message'         // Retry failed message
'reconnect-bridge'      // Attempt to reconnect
'bridge-reset'          // Reset bridge state

Usage Examples:

// Handle bridge errors
bridge.on('bridge-error', (error) => {
  console.error('Bridge communication error:', error);
  
  // Attempt recovery
  setTimeout(() => {
    bridge.send('reconnect-bridge', {});
  }, 1000);
});

// Handle connection loss
bridge.on('connection-lost', () => {
  console.warn('DevTools connection lost');
  // Show disconnected state in UI
  showDisconnectedState();
});

bridge.on('connection-restored', () => {
  console.log('DevTools connection restored');
  // Restore normal operation
  hideDisconnectedState();
  // Resync data
  bridge.send('request-full-sync', {});
});

Performance Considerations

Message Batching Strategy

The bridge uses intelligent batching to optimize performance:

// Messages are batched within 100ms windows
// Multiple tree operations become single batch
bridge.send('tree-operation', { type: 'ADD', id: 1, parentID: 0 });
bridge.send('tree-operation', { type: 'ADD', id: 2, parentID: 1 });
bridge.send('tree-operation', { type: 'UPDATE', id: 1, name: 'NewName' });

// Results in single batched message:
// {
//   event: 'batched-operations',
//   payload: [
//     { type: 'ADD', id: 1, parentID: 0 },
//     { type: 'ADD', id: 2, parentID: 1 },
//     { type: 'UPDATE', id: 1, name: 'NewName' }
//   ]
// }

Transferable Objects

Use transferable objects for large data to improve performance:

// Send large profiling data efficiently
const profilingBuffer = new ArrayBuffer(1024 * 1024);
bridge.send('profiling-data', profilingBuffer, [profilingBuffer]);

// Send element tree data
const treeBuffer = serializeElementTree(elementTree);
bridge.send('tree-data', treeBuffer, [treeBuffer]);

Memory Management

The bridge includes cleanup mechanisms to prevent memory leaks:

// Clean up bridge resources
bridge.on('shutdown', () => {
  // Clear message queues
  bridge._messageQueue = [];
  
  // Clear timeouts
  if (bridge._timeoutID) {
    clearTimeout(bridge._timeoutID);
  }
  
  // Remove all listeners
  bridge.removeAllListeners();
});

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