使用 extend-chrome/messages 从后台脚本向内容脚本发送消息时出错

Get error while using extend-chrome/messages while sending messgae from background script to content script

我正在使用 this 库进行消息传递。

我有这样的后台脚本

import { sendUrlInfo, waitForUrl } from 'utils/messaging';
import URL from 'url-parse';

chrome.webNavigation.onHistoryStateUpdated.addListener((details) => {
  const url = new URL(details.url);
  console.log('sending', url.hostname, url.pathname);
  sendUrlInfo(new URL(details.url));
});

chrome.webNavigation.onCompleted.addListener((details) => {
  if (details.url !== 'about:blank') {
    const url = new URL(details.url);
    console.log('sending', url.hostname, url.pathname);
    sendUrlInfo(new URL(details.url));
  }
});

根据文档,我 message.js 如下所示

import { getMessage } from '@extend-chrome/messages';
import URL from 'url-parse';

const messageTypes = {
  URL_INFO: 'URL_INFO',
};

export const [sendUrlInfo, urlStream, waitForUrl] = getMessage<URL>(
  messageTypes.URL_INFO,
);

现在是我用 React 编写的内容脚本 所以我试图在安装组件时订阅流

import React, { useState, useEffect, useRef } from 'react';

import Editor from 'content/components/Editor';
import Opener from 'content/components/Opener';
import { urlStream, waitForUrl } from 'utils/messaging';

const Main: React.FC = () => {
  const [isOpen, setIsOpen] = useState(false);
  const [showContent, setShowContent] = useState(false);

  const editorRef = useRef<HTMLTextAreaElement | null>(null);

  useEffect(() => {
    console.log('MOunted');
    urlStream.subscribe(([url]) => {
      console.log('Received', url.hostname, url.pathname);
      if (url.hostname === 'www.youtube.com' && url.pathname === '/watch') {
        if (!showContent) setShowContent(true);
      } else {
        if (showContent) setShowContent(false);
      }
    });
  }, []);

  useEffect(() => {
    document.addEventListener('keydown', onKeyPress);
    return () => {
      document.removeEventListener('keydown', onKeyPress);
    };
  });

  const onKeyPress = (e: KeyboardEvent) => {
    if (e.ctrlKey && e.which === 192) {
      e.preventDefault();
      setIsOpen(!isOpen);
    }
  };

  if (!showContent) return <></>;

  return (
    <>
      <div>test</div>
      <Opener isOpen={isOpen} onClick={() => setIsOpen(true)} />
      <Editor
        isOpen={isOpen}
        ref={editorRef}
        onClose={() => setIsOpen(false)}
      />
    </>
  );
};

export default Main;

我在后台脚本控制台中遇到的错误是

Could not establish connection. Receiving end does not exist

据我所知,后台脚本正在尝试发送消息,但可观察到的内容脚本尚未订阅。作为页面加载后的内容脚本 运行。 如果这是问题所在,是否有任何方法可以正确使用此库。

顺便说一句,如果我们像这样使用普通 chrome api

chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
    chrome.tabs.sendMessage(
        tabs[0].id,
        message,
        function () {
                console.log("msg sent")     
        }
    );
});

并使用 onMessage 接收消息。

后台页面需要知道我们正在向选项卡发送消息。除非定义 options.tabId,否则 sendUrlInfo 使用 chrome.runtime.sendMessage.

发送消息

在后台脚本中将选项参数添加到 sendUrlInfo:

chrome.webNavigation.onHistoryStateUpdated.addListener((details) => {
  const url = new URL(details.url);
  console.log('sending', url.hostname, url.pathname);

  const options = { tabId: details.tabId }; // Add options.tabId here
  sendUrlInfo(new URL(details.url), options);
});