or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

backend-agent.mdbridge-communication.mddata-hydration.mddevtools-ui.mdfrontend-store.mdhook-system.mdindex.mdperformance-profiling.md
tile.json

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();
});