Skip to Content
LaunchExt | Chrome 扩展开发平台 (Next.js + Plasmo) 🚀 Read more → 
文档Framework消息通信

消息传递 API

Plasmo 的消息传递 API 使得扩展不同部分之间的通信变得简单。在您的 messages 目录中添加一个文件,Plasmo 将处理所有其余工作。Plasmo 消息传递是一个声明式、类型安全、基于函数的、基于 Promise 的 API,用于在扩展组件之间发送、转发和接收消息。

安装

1. 安装依赖

@plasmohq/messaging 库保存在一个单独的仓库中。您首先需要使用包管理器安装它。

pnpm install @plasmohq/messaging

2. 创建后台文件夹和文件

@plasmohq/messaging 库要求后台服务工作者位于 background/index.ts 文件夹中,所有消息处理程序位于 background/* 文件夹中。

如果您已经有 background.tsbackground.js 文件,您需要创建一个 background 文件夹并将脚本移动到 background/index.tsbackground/index.js

如果您还没有 background 文件夹,请创建一个 background 文件夹并创建一个新的空 background/index.tsbackground/index.js 文件。

现在您将能够在 background/ 子文件夹中创建新的处理程序。例如,要创建一个名为 pingmessages 处理程序,您需要创建 background/messages/ping.ts。请参阅文档的其余部分,了解可用的不同类型的处理程序以及如何配置它们。

此时,您的文件夹结构可能如下所示:

新的文件夹结构
. ├── background ├── index.ts └── messages └── ping.ts

3. 生成静态类型

在编译时,Plasmo 将为您的所有消息处理程序生成静态类型。如果您正在运行开发服务器,这将自动发生;每次构建时也会自动发生。sendToBackgroundrelayMessage 函数都接受一个 name 字段作为其参数对象的一部分;这个 name 字段将被静态类型化为您的所有消息处理程序的名称。

⚠️

注意:初始类型错误

如果您收到诸如 "name" is never 之类的类型错误,这是因为 Plasmo 需要编译您的处理程序类型。要解决此问题:

  1. 运行开发服务器
  2. 重新启动编辑器中的 TypeScript 服务器

4. 完成

您现在已经成功安装了 Plasmo 的消息传递库。

快速概览

消息传递 API一次性长连接
消息流扩展页面/内容脚本后台服务工作者
转发流网页内容脚本/后台服务工作者
端口扩展页面/内容脚本后台服务工作者
端口后台服务工作者扩展页面/内容脚本
端口 + 转发后台服务工作者网页

示例

消息流

使用消息流在扩展页面、标签页或内容脚本与后台服务工作者之间发起一次性消息。此流程对于将繁重的计算卸载到后台服务工作者或绕过 CORS 非常有用。

后台服务工作者是一个具有 REST 风格 API 处理程序的消息中心。要创建消息处理程序,请在 background/messages 目录中创建一个 ts 模块。文件名应为消息名称,默认导出应为处理程序函数:

background/messages/ping.ts
import type { PlasmoMessaging } from "@plasmohq/messaging" const handler: PlasmoMessaging.MessageHandler = async (req, res) => { const message = await querySomeApi(req.body.id) res.send({ message }) } export default handler

扩展页面、内容脚本或标签页可以使用 @plasmohq/messaging 库向这些处理程序发送消息。由于 Plasmo 框架在幕后编排您的处理程序,消息名称是类型化的,并将在您的编辑器中启用 IntelliSense:

popup.tsx
import { sendToBackground } from "@plasmohq/messaging" ... const resp = await sendToBackground({ name: "ping", body: { id: 123 } }) console.log(resp)

要从主世界的内容脚本发送消息,您需要在请求中包含扩展的 ID。您的扩展 ID 可以在构建并将其添加到浏览器后,在 Chrome 的扩展管理窗口中找到。

contents/componentInTheMainWorld.tsx
import { sendToBackground } from "@plasmohq/messaging" import type { PlasmoCSConfig } from "plasmo" export const config: PlasmoCSConfig = { matches: ["<all_urls>"], world: "MAIN" } ... const resp = await sendToBackground({ name: "ping", body: { id: 123 }, extensionId: 'llljfehhnoeipgngggpomjapaakbkyyy' // 在 Chrome 的扩展管理器中找到此 ID }) console.log(resp)

转发流

⚠️

注意: 转发消息传递 API 处于公开 alpha 预览阶段:预计会有错误、不完整/有漏洞的抽象以及未来的 API 更改。请通过此链接向我们报告您遇到的任何问题。

转发流支持目标网页和后台服务工作者之间的通信,使用称为转发的轻量级消息处理程序。此转发器在内容脚本中使用 relayMessage 函数注册。

relayMessage 函数抽象了 window.postMessage 机制,注册一个监听器,检查匹配相同来源的消息并将其转发到后台服务工作者。这些消息随后由在 background/messages 下注册的相应消息流处理程序处理。

sendToBackgroundViaRelay 函数通过转发器发送消息并等待响应。它为每条消息生成唯一的实例 ID,以确保正确处理和响应跟踪。

您可以在 GitHub 仓库  中查看这些函数的实现。

此方法提供了 Chrome 扩展文档中描述的 “externally_connectable”  方法的替代方案。

设置转发器

要设置转发器,请在内容脚本中使用 relayMessage 函数。一个内容脚本可以有多个转发器。给定上一个示例中的 ping 消息处理程序和网站 www.plasmocn.org

contents/plasmo.ts
import type { PlasmoCSConfig } from "plasmo" import { relayMessage } from "@plasmohq/messaging" export const config: PlasmoCSConfig = { matches: ["http://www.plasmocn.org/*"] // 仅从此域转发消息 } relayMessage({ name: "ping" })

在目标网页的代码中(例如 plasmo.com),您可以使用 sendToBackgroundViaRelay 通过注册的转发器发送消息,如下所示:

pages/index.tsx
import { sendToBackgroundViaRelay } from "@plasmohq/messaging" ... const resp = await sendToBackgroundViaRelay({ name: "ping" }) console.log(resp)

要在 chrome.runtime 不可用的上下文中转发消息,您可以使用 relay 函数:

sandbox.tsx
import { relayMessage } from "@plasmohq/messaging" relayMessage( { name: "ping" }, async (req) => { console.log("某些消息被转发了:", req) return { message: "来自沙盒的问候" } } )

端口

⚠️

端口消息传递 API 处于公开 alpha 预览阶段:预计会有错误、不完整/有漏洞的抽象以及未来的 API 更改。请通过此链接向我们报告您遇到的任何问题。

消息传递端口 API 是 Chrome 运行时 端口 API  的高级抽象,用于与后台服务工作者建立长连接。

当前实现侧重于建立与后台服务工作者中端口监听器的连接:

要创建 BGSW 端口处理程序,请在 background/ports 目录中创建一个 ts 模块。文件名将是端口名称,默认导出将是处理程序函数:

background/ports/mail.ts
import type { PlasmoMessaging } from "@plasmohq/messaging" const handler: PlasmoMessaging.PortHandler = async (req, res) => { console.log(req) res.send({ message: "来自端口处理程序的问候" }) } export default handler

在您的扩展页面中,使用 @plasmohq/messaging/port 下的 getPort 实用程序获取端口,或者使用 usePort 钩子,请注意 usePort 目前依赖于 React 钩子,因此您需要在 React 组件中使用它。此示例显示了在 Svelte 组件中使用 getPort

popup.svelte
<script lang="ts"> import { getPort } from "@plasmohq/messaging/port" import { onMount, onDestroy } from "svelte" let output = "" const messageListener = (msg) => { output = msg } const mailPort = getPort("mail") onMount(() => { mailPort.onMessage.addListener(messageListener) }) onDestroy(() => { mailPort.onMessage.removeListener(messageListener) }) function handleSubmit() { mailPort.postMessage({ body: { hello: "world" } }) } </script> <div>{output}</div>

以下是 React 中使用 usePort 的示例,数据将始终反映来自端口处理程序的最新响应:

tabs/delta.tsx
import { usePort } from "@plasmohq/messaging/hook" function DeltaTab() { const mailPort = usePort("mail") return ( <div> {mailPort.data?.message} <button onClick={async () => { mailPort.send({ hello: "world" }) }}> 发送数据 </button> </div> ) } export default DeltaTab

端到端类型安全(进行中)

端到端请求/响应主体类型安全正在 #334  进行中。在此期间,您可以使用提供的泛型类型:

background/messages/ping.ts
import type { PlasmoMessaging } from "@plasmohq/messaging" export type RequestBody = { id: number } export type ResponseBody = { message: string } const handler: PlasmoMessaging.MessageHandler< RequestBody, ResponseBody > = async (req, res) => { console.log(req.body.id) res.send({ message: "来自后台的问候" }) } export default handler
popup.tsx
import { sendToBackground } from "@plasmohq/messaging" import type { RequestBody, ResponseBody } from "~background/messages/ping" ... const resp = await sendToBackground<RequestBody, ResponseBody>({ name: "ping", body: { id: 123 } }) console.log(resp)
最后更新于