Manifest V3扩展Popup与Background Service Worker无法建立连接问题
原有配置此前可正常运行,确认配置本身无误,后续调试始终报错:
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
全网未找到匹配现有配置的解决方案。
最小复现示例
dist目录结构:
dist/background.js dist/index.html dist/manifest.json dist/popup.js dist/runtime.js dist/vendors.js other misc files
manifest.json配置:
// manifest.json { ... "background": { "service_worker": "background.js" }, ... }
src/components/App.tsx代码:
// src/components/App.tsx export default function App(): JSX.Element { ... useEffect(() => { chrome.runtime.sendMessage({ type: 'someMessage' }, ({ data }) => { console.log(data); }); }, []); ... }
src/background.ts代码:
// src/background.ts import { TSentResponse } from "./typings/background"; import { executeResponse } from "./utils/background"; console.log('sanity check'); // <=== 未触发 🤔 // 也未被调用 😥 const handleMessage = (req: { type: string }, sender: chrome.runtime.MessageSender, res: (response?: unknown) => void) => { switch (req.type) { case 'someMessage': // 一个IIFE(此前运行正常) break; default: break; } return true; // 适配异步逻辑 }; chrome.runtime.onMessage.addListener(handleMessage);
Service Worker在扩展管理页显示已注册,但是从扩展管理页打开的Service Worker开发者工具中看不到上述background.ts的日志输出,仅popup的开发者工具可以看到两个报错:
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
Error handling response: TypeError: Cannot destructure property 'data' of 'undefined' as it is undefined.
同时Service Worker实际未完成注册,此前版本可正常完成注册。
排查过程
第一次排查
初步判断问题由webpack导致,将打包输出的dist/background.js替换为以下简化代码:
console.log("background is running"); // 现在可见 ✅ const handler = (req, sender, sendResponse) => { switch (req.type) { case "message": sendResponse({ data: "hi" }); break; default: break; } }; chrome.runtime.onMessage.addListener(handler);
此时Service Worker控制台日志输出正常,popup也能正常收到响应,无报错。
第二次排查
检查webpack打包输出的background.js内容,发现业务代码被包裹在一个函数中但从未执行:
{ /***/ "./src/background.ts": /*!***************************!\ !*** ./src/background.ts ***! \***************************/ /***/ (function () { console.log("background is running"); const handler = (req, sender, sendResponse) => { switch (req.type) { case "message": sendResponse({ data: "hi" }); break; default: break; } }; chrome.runtime.onMessage.addListener(handler); /***/ }) // <==== 加()转为IIFE即可正常运行! },
手动添加括号改为IIFE后可正常运行,但该方案仅在background.js无import语句时生效,只要存在导入语句就会提示background脚本不合法。尝试在manifest.json的background配置中添加"type": "module"属性也无效:
// manifest.json { ... "background": { "service_worker": "background.js", "type": "module" }, ... }
最终根因确认
问题由webpack的vendor拆分优化配置导致,对应配置如下:
// webpack.config.json { ... "optimization": { "runtimeChunk": "single", "splitChunks": { "cacheGroups": { "vendor": { "test": /[\\/]node_modules[\\/]/, "name": "vendors", "enforce": true, "chunks": "all", }, }, }, }, ... }
解决方案
删除上述webpack优化配置后功能即可恢复正常。该配置仅为性能优化项,若导致功能异常可优先移除。
内容的提问来源于stack exchange,提问作者lbragile

