You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vite开发模式下Chrome扩展sendMessage报无法建立连接错误求助

解决Vite开发模式下Chrome扩展新标签页sendMessage竞态问题

在开发Chrome扩展时,遇到Vite开发模式下新标签页加载后chrome.tabs.sendMessage报错Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.的问题。生产环境使用Rollup构建静态HTML时正常,但Vite开发模式下页面动态加载导致脚本未就绪,必须用setTimeout延迟发送才能解决,以下是三种可靠的优化方案:

方案1:基于消息双向确认的可靠通信

核心思路是让新标签页的脚本加载完成后主动通知Background,Background收到通知后再发送目标数据,彻底避免竞态问题。

Background端代码修改

export function launchSvgGobbler() {
  // 存储待发送的标签页数据
  let pendingTabTask = null;

  // 监听新标签页的就绪通知
  chrome.runtime.onMessage.addListener((message, sender) => {
    if (message.type === 'TAB_READY' && pendingTabTask?.tabId === sender.tab.id) {
      // 标签页就绪,发送业务数据
      chrome.tabs.sendMessage(sender.tab.id!, pendingTabTask.data);
      pendingTabTask = null;
    }
  });

  chrome.action.onClicked.addListener(async ({ url }) => {
    try {
      const tab = await utils.createNewTab();
      // 暂存数据和标签ID,等待就绪通知
      pendingTabTask = {
        tabId: tab.id!,
        data: { data: 'data' }
      };
    } catch (error) {
      console.log('Error launching', error);
      pendingTabTask = null;
    }
  });
}

新标签页脚本修改

在新标签页的入口脚本中,页面初始化完成后发送就绪通知,并监听数据消息:

// 新标签页入口文件(如 src/pages/newTab/index.js)
window.addEventListener('DOMContentLoaded', () => {
  // 通知Background:当前标签页脚本已就绪
  chrome.runtime.sendMessage({ type: 'TAB_READY' });
});

// 监听Background发来的业务数据
chrome.runtime.onMessage.addListener((message) => {
  if (message.data) {
    // 处理收到的数据
    console.log('Received data:', message.data);
  }
});

方案2:优化标签页加载完成的判断逻辑

通过在createNewTab中增加测试消息的重试逻辑,确保标签页脚本真正就绪后再返回Promise。

修改createNewTab函数

/**
 * Awaits the loading of a newly created tab and return the tab config.
 * @param url The url to open relative to the extension. Defaults to index.html.
 */
export function createNewTab(url = 'index.html'): Promise<chrome.tabs.Tab> {
  return new Promise((resolve) => {
    chrome.tabs.create({ url, active: true }, (tab) => {
      const listener = async (updatedTabId, changeInfo, updatedTab) => {
        if (
          tab.id &&
          updatedTabId === tab.id &&
          changeInfo.status === 'complete' &&
          updatedTab.status === 'complete'
        ) {
          if (process.env.NODE_ENV === 'development') {
            try {
              // 发送测试消息,验证脚本是否就绪
              await chrome.tabs.sendMessage(tab.id!, { type: 'PING' });
              // 验证成功,移除监听并返回标签页
              chrome.tabs.onUpdated.removeListener(listener);
              resolve(updatedTab);
            } catch (e) {
              // 验证失败,继续等待(下一次onUpdated触发时重试)
              return;
            }
          } else {
            chrome.tabs.onUpdated.removeListener(listener);
            resolve(updatedTab);
          }
        }
      };

      chrome.tabs.onUpdated.addListener(listener);
    });
  });
}

新标签页脚本增加PING响应

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  // 响应测试消息
  if (message.type === 'PING') {
    sendResponse('PONG');
  }
  // 其他业务消息处理...
});

方案3:让Vite开发模式生成静态HTML

配置Vite在开发模式下也生成静态index.html文件,模拟生产环境的加载方式:

// vite.config.js
import { defineConfig } from 'vite';
import copy from 'vite-plugin-static-copy';

export default defineConfig({
  plugins: [
    process.env.NODE_ENV === 'development' && copy({
      targets: [
        { src: 'index.html', dest: 'dist' }
      ]
    })
  ].filter(Boolean),
  // 确保开发服务器的资源路径和扩展匹配
  server: {
    port: 5173,
    strictPort: true
  }
});

之后修改createNewTab的默认URL指向生成的静态文件路径,同时调整扩展manifest中的权限和资源路径配置。

内容的提问来源于stack exchange,提问作者Ross Moody

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 13:05:54