Skip to content

@pt/cross-bridge

一个强大的跨域通信插件,支持独立标签页、iframe、完全跨域等多种通信场景。

📚 详细文档

为了帮助你更好地理解和使用 CrossBridge,我们准备了详细的文档指南。建议按以下顺序阅读:

  1. 📖 00_PROJECT_STATUS.md (项目总览) - 必读!了解项目当前的能力地图和状态。
  2. 🎯 01_REQUIREMENTS.md (需求规格) - 了解项目的背景、目标和核心需求。
  3. 🏗️ 02_ARCHITECTURE.md (架构设计) - 深入了解系统的分层架构和设计原理。
  4. 🔧 03_TECHNICAL_DESIGN.md (技术实现) - 查看具体的技术实现细节和代码结构。
  5. 💻 04_USAGE_EXAMPLES.md (全场景示例) - 核心!涵盖同域、跨域、iframe 等所有场景的代码示例。
  6. 📄 05_SINGLE_PAGE_GUIDE.md (单页指南) - 专为单页应用 (index.html) 设计的快速上手指南。
  7. ⚡ 06_PERFORMANCE.md (性能优化) - 进阶阅读,了解如何进行性能调优。

✨ 特性

  • 🚀 多种通信方式: 支持 SharedWorker、PostMessage、WebRTC P2P、WebSocket 中继等
  • 🎯 智能路由: 根据通信场景和数据特征自动选择最优通信方式
  • 📦 消息队列: 支持消息缓存和延迟消费,解决页面未加载问题
  • 🔄 页面角色管理: 支持页面的多种角色(父页面、子页面、独立页面、混合角色)
  • 🌐 完全跨域: 支持不同一级域名间的通信
  • 高性能: 同域通信延迟 < 1ms,跨域 P2P 延迟 < 50ms
  • 🛠️ TypeScript: 完整的类型定义支持
  • 🔧 易于集成: 与 mitt 等事件系统无缝集成

📦 安装

bash
# 使用 pnpm
pnpm add @pt/cross-bridge

# 使用 npm
npm install @pt/cross-bridge

# 使用 yarn
yarn add @pt/cross-bridge

🚀 快速开始

基础使用

typescript
import { CrossBridge } from '@pt/cross-bridge';

// 创建 CrossBridge 实例
const bridge = new CrossBridge({
  pageId: 'main-page',
  role: 'parent',
  adapters: ['shared-worker', 'post-message'],
  debug: true,
});

// 连接
await bridge.connect();

// 监听消息
bridge.on('data-updated', (data, from) => {
  console.log(`收到来自 ${from} 的数据:`, data);
});

// 发送消息
bridge.emit('user-action', { type: 'click', target: 'button' });

// 广播消息
bridge.broadcast('theme-changed', { theme: 'dark' });

// 发送给特定页面
bridge.sendTo('child-page', 'command', { action: 'refresh' });

主页面(包含 iframe)

typescript
const mainBridge = new CrossBridge({
  pageId: 'main-page',
  role: 'parent',
  adapters: ['shared-worker', 'post-message'],
});

await mainBridge.connect();

// 注册 iframe 页面
mainBridge.registerPage('data-analysis', {
  role: 'child',
  type: 'iframe',
  origin: 'http://console-dev1.e-tudou.com',
  domain: 'console-dev1.e-tudou.com',
  element: document.getElementById('data-iframe'),
  capabilities: ['data-processing'],
});

// 监听子页面消息
mainBridge.on('data-updated', (data, from) => {
  console.log(`数据更新来自 ${from}:`, data);
  // 转发给其他页面
  mainBridge.sendTo('agent-chat', 'external-data-change', data);
});

iframe 子页面

typescript
const childBridge = new CrossBridge({
  pageId: 'data-analysis',
  role: 'child',
  adapters: ['post-message'],
});

await childBridge.connect();

// 监听父页面消息
childBridge.on('theme-changed', (themeData) => {
  document.body.className = `theme-${themeData.theme}`;
});

// 向父页面发送数据
childBridge.emit('data-updated', {
  type: 'analysis-result',
  data: { result: 'success', count: 100 },
  timestamp: Date.now(),
});

独立标签页

typescript
const tabBridge = new CrossBridge({
  pageId: 'standalone-tab-1',
  role: 'standalone',
  adapters: ['shared-worker'],
});

await tabBridge.connect();

// 监听其他标签页消息
tabBridge.on('user-login', (userInfo) => {
  console.log('用户登录:', userInfo);
  syncUserState(userInfo);
});

// 发送消息给主页面
tabBridge.sendTo('main-page', 'tab-action', {
  action: 'file-selected',
  fileId: '12345',
});

单页应用使用

CrossBridge 完全支持在单个 HTML 页面中使用,特别适合以下场景:

1. 被 iframe 内嵌的子页面

html
<!DOCTYPE html>
<html>
  <head>
    <title>我的功能页面</title>
  </head>
  <body>
    <h1>简单功能页面</h1>
    <button id="action-btn">执行操作</button>

    <!-- 引入 CrossBridge -->
    <script src="./dist/cross-bridge.umd.js"></script>

    <script>
      // 初始化为子页面角色
      const bridge = new CrossBridge({
        pageId: 'my-feature-page',
        role: 'child', // 子页面角色
        adapters: ['post-message', 'shared-worker'],
        debug: true,
      });

      // 连接
      bridge.connect().then(() => {
        console.log('子页面已连接到 CrossBridge');
      });

      // 监听来自父页面的消息
      bridge.on('parent-message', (data) => {
        console.log('收到父页面消息:', data);
      });

      // 向父页面发送消息
      document.getElementById('action-btn').addEventListener('click', () => {
        bridge.emit('child-action', {
          action: 'button-click',
          timestamp: Date.now(),
          pageId: bridge.pageId,
        });
      });
    </script>
  </body>
</html>

2. 独立部署的功能页面

html
<!DOCTYPE html>
<html>
  <head>
    <title>独立功能页面</title>
  </head>
  <body>
    <h1>独立功能页面</h1>

    <script src="./dist/cross-bridge.umd.js"></script>
    <script>
      // 初始化为独立页面角色
      const bridge = new CrossBridge({
        pageId: 'standalone-page',
        role: 'standalone', // 独立页面角色
        adapters: ['shared-worker'], // 可与同域其他页面通信
        debug: true,
      });

      bridge.connect().then(() => {
        console.log('独立页面已连接');

        // 可以与同域的其他页面通信
        bridge.broadcast('page-ready', {
          pageType: 'feature-page',
          capabilities: ['data-export', 'user-management'],
        });
      });
    </script>
  </body>
</html>

3. URL 参数自动配置

支持通过 URL 参数自动配置页面角色和连接:

html
<!-- 自动设置为子页面角色并自动连接 -->
<iframe src="my-page.html?role=child&autoConnect=true"></iframe>

<!-- 自动设置为独立页面角色 -->
<a href="my-page.html?role=standalone" target="_blank">打开功能页面</a>

在页面中检测 URL 参数:

javascript
// 检测 URL 参数并自动配置
const urlParams = new URLSearchParams(window.location.search);
const role = urlParams.get('role') || 'standalone';
const autoConnect = urlParams.get('autoConnect') === 'true';

const bridge = new CrossBridge({
  pageId: `page-${Date.now()}`,
  role: role,
  adapters: ['post-message', 'shared-worker'],
  debug: true,
});

if (autoConnect) {
  bridge.connect();
}

4. 使用场景示例

简单功能页面部署后作为 iframe 内嵌使用:

html
<!-- 父页面 -->
<!DOCTYPE html>
<html>
  <body>
    <h1>主应用</h1>
    <iframe
      src="https://my-domain.com/feature-page.html?role=child&autoConnect=true"
      width="100%"
      height="500px"
    ></iframe>

    <script src="./dist/cross-bridge.umd.js"></script>
    <script>
      const parentBridge = new CrossBridge({
        pageId: 'main-app',
        role: 'parent',
        adapters: ['post-message', 'shared-worker'],
        debug: true,
      });

      parentBridge.connect().then(() => {
        // 监听子页面消息
        parentBridge.on('child-action', (data) => {
          console.log('子页面操作:', data);
        });

        // 发送消息给子页面
        parentBridge.broadcast('parent-message', {
          type: 'config-update',
          theme: 'dark',
        });
      });
    </script>
  </body>
</html>

🎯 高级配置

完全跨域通信

typescript
const bridge = new CrossBridge({
  pageId: 'cross-domain-page',
  role: 'parent',
  adapters: [
    {
      type: 'websocket-relay',
      config: {
        relayServer: 'wss://bridge.e-tudou.com/relay',
        authentication: {
          token: 'your-auth-token',
          domain: 'example.com',
        },
      },
    },
    {
      type: 'iframe-bridge',
      config: {
        bridgeUrl: 'https://bridge.e-tudou.com/bridge.html',
      },
    },
  ],
});

消息队列配置

typescript
const bridge = new CrossBridge({
  pageId: 'advanced-page',
  role: 'parent',
  adapters: ['shared-worker', 'post-message'],
  queue: {
    messageTypes: {
      'critical-alert': {
        ttl: 600000, // 10分钟
        storage: 'local', // 持久化到 localStorage
        priority: 0, // 最高优先级
        persistent: true,
      },
      'user-interaction': {
        ttl: 180000, // 3分钟
        storage: 'session', // 会话存储
        priority: 1,
        persistent: true,
      },
    },
    maxQueueSize: 1000,
    cleanupInterval: 30000,
  },
});

性能优化配置

typescript
const bridge = new CrossBridge({
  pageId: 'optimized-page',
  role: 'parent',
  adapters: ['shared-worker', 'post-message', 'webrtc-p2p'],
  optimization: {
    enableBatching: true, // 启用消息批处理
    enableCompression: true, // 启用数据压缩
    enableP2P: true, // 启用 P2P 直连
    fallbackChain: [
      // 降级链
      'webrtc-p2p',
      'shared-worker',
      'post-message',
    ],
    performanceMonitoring: true,
  },
});

与 mitt 集成

typescript
import mitt from 'mitt';

const globalEvents = mitt();

const bridge = new CrossBridge({
  pageId: 'mitt-integration',
  role: 'parent',
  adapters: ['shared-worker'],
  eventBus: globalEvents,
  eventMapping: {
    'cross-bridge:message': 'global:cross-message',
    'cross-bridge:page-connected': 'global:page-online',
  },
});

// mitt 事件会自动同步到 CrossBridge
globalEvents.on('user-action', (data) => {
  bridge.broadcast('user-action', data);
});

CrossBridge 类

构造函数

typescript
new CrossBridge(config: CrossBridgeConfig)

方法

方法描述参数返回值
connect()连接所有适配器-Promise<void>
disconnect()断开所有连接-void
emit(event, data, target?)发送事件消息event: string, data: any, target?: string | string[]void
broadcast(event, data)广播消息event: string, data: anyvoid
sendTo(pageId, event, data)发送给特定页面pageId: string, event: string, data: anyvoid
on(event, handler)监听事件event: string, handler: EventHandlervoid
off(event, handler?)移除事件监听器event: string, handler?: EventHandlervoid
once(event, handler)一次性事件监听器event: string, handler: EventHandlervoid
registerPage(id, info)注册页面信息id: string, info: PageInfovoid
unregisterPage(id)注销页面id: stringvoid
getConnectedPages()获取已连接页面列表-PageInfo[]
getPageInfo(id)获取页面信息id: stringPageInfo | null
isConnected()检查是否已连接-boolean
getConnectionStatus()获取连接状态-ConnectionStatus

配置接口

CrossBridgeConfig

typescript
interface CrossBridgeConfig {
  pageId: string; // 页面唯一标识
  role: PageRole; // 页面角色
  adapters: (AdapterType | AdapterConfig)[]; // 适配器配置
  queue?: Partial<QueueConfig>; // 消息队列配置
  storage?: Partial<StorageConfig>; // 存储配置
  optimization?: Partial<OptimizationConfig>; // 性能优化配置
  eventBus?: Emitter<any>; // 外部事件总线
  eventMapping?: Record<string, string>; // 事件映射
  debug?: boolean; // 调试模式
}

PageRole

typescript
type PageRole = 'parent' | 'child' | 'standalone' | 'hybrid';
  • parent: 父页面,包含 iframe
  • child: 子页面,被嵌入的 iframe
  • standalone: 独立页面,独立的浏览器标签页
  • hybrid: 混合角色,既是父页面又是子页面

AdapterType

typescript
type AdapterType =
  | 'shared-worker' // SharedWorker 适配器
  | 'post-message' // PostMessage 适配器
  | 'broadcast-channel' // BroadcastChannel 适配器
  | 'webrtc-p2p' // WebRTC P2P 适配器
  | 'iframe-bridge' // iframe 桥接适配器
  | 'websocket-relay'; // WebSocket 中继适配器

🏗️ 架构设计

分层架构

┌─────────────────────────────────────────┐
│              应用层                      │
│  (用户代码,事件处理,业务逻辑)           │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│              API 层                     │
│     (CrossBridge 主类,统一接口)         │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│             核心层                       │
│  (消息路由,队列管理,生命周期管理)       │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│            适配器层                      │
│ (SharedWorker, PostMessage, WebRTC...)  │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│            存储层                        │
│  (Memory, SessionStorage, LocalStorage)  │
└─────────────────────────────────────────┘

通信流程

  1. 消息发送: 应用层 → API 层 → 核心层 → 适配器层
  2. 消息接收: 适配器层 → 核心层 → API 层 → 应用层
  3. 智能路由: 根据目标和数据特征选择最优适配器
  4. 消息队列: 离线页面的消息缓存和延迟投递
  5. 生命周期: 页面连接状态管理和自动重连

🚀 性能表现

通信方式延迟吞吐量适用场景
SharedWorker< 1ms> 1000 msg/s同域标签页
PostMessage< 1ms> 1000 msg/siframe 通信
WebRTC P2P< 50ms> 100 msg/s跨域高频数据
iframe 桥接< 100ms> 50 msg/s跨域中频数据
WebSocket 中继< 200ms> 10 msg/s跨域低频重要数据

🔧 开发指南

本地开发

bash
# 安装依赖
pnpm install

# 开发模式
pnpm dev

# 构建
pnpm build

# 运行示例
cd examples && python -m http.server 8080

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📄 许可证

MIT License

Released under the MIT License.