Framework
Messaging

メッセージング API

See LicenseNPM InstallFollow PlasmoHQ on TwitterWatch our Live DEMO every FridayJoin our Discord for support and chat about our projects

Plasmo のメッセージング API を使用すると、拡張機能の異なる部分間の通信が容易になります。messages ディレクトリにファイルを追加するだけで、Plasmo が残りの処理をすべて行います。Plasmo メッセージングは、宣言型で、型安全、関数型、Promise ベースの API で、拡張機能コンポーネント間でメッセージの送受信、中継を行います。

インストール

1. 依存関係のインストール

@plasmohq/messaging ライブラリは、別のリポジトリに保持されています。まず、パッケージマネージャーを使用してインストールする必要があります。

pnpm install @plasmohq/messaging

2. background フォルダとファイルの作成

@plasmohq/messaging ライブラリでは、バックグラウンドサービスワーカーが background/index.ts フォルダ内に存在し、すべてのメッセージハンドラーが background/* フォルダ内に存在する必要があります。

既に background.ts または background.js ファイルがある場合は、background フォルダを作成し、スクリプトを background/index.ts または background/index.js に移動する必要があります。

background フォルダがまだない場合は、background フォルダを作成し、新しい空の background/index.ts または background/index.js ファイルを作成します。

これで、background/ サブフォルダ内に新しいハンドラーを作成できるようになります。例えば、ping という名前の messages ハンドラーを作成するには、background/messages/ping.ts を作成します。利用可能なさまざまなタイプのハンドラーとその設定方法については、ドキュメントの残りの部分を参照してください。

この時点で、フォルダ構造は次のようになる可能性があります。

New Folder Structure
.
├── background
├── index.ts
└── messages
└── ping.ts

3. 静的型の生成

コンパイル時に、Plasmo はすべてのメッセージハンドラーの静的型を生成します。開発サーバーが実行されている場合は自動的に実行されます。ビルドするたびに自動的に実行されます。sendToBackground および relayMessage 関数は、どちらもパラメーターオブジェクトの一部として name フィールドを受け取ります。この name フィールドは、すべてのメッセージハンドラーの名前で静的に型付けされます。

⚠️

注意: 最初の型エラー

"name" is never のような型エラーが発生する場合は、Plasmo がハンドラー型をコンパイルする必要があるためです。解決するには:

  1. 開発サーバーを実行する
  2. エディターで TypeScript サーバーを再起動する

4. 以上です

これで、Plasmo のメッセージングライブラリのインストールが完了しました。

TL;DR

メッセージング 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' // find this in chrome's extension manager
})
 
console.log(resp)

リレーフロー

⚠️

注意: リレーメッセージングAPIはパブリックアルファプレビュー版です。バグ、不完全/漏洩した抽象化、および将来のAPIの変更を予期してください。遭遇した問題については、このリンクからお知らせください

リレーフローは、リレーと呼ばれる軽量なメッセージハンドラーを使用して、ターゲットウェブページとバックグラウンドサービスワーカー間の通信を可能にします。このリレーは、コンテンツスクリプトrelayMessage関数を使用して登録されます。

relayMessage関数はwindow.postMessageメカニズムを抽象化し、同じオリジンに一致するメッセージを検出してバックグラウンドサービスワーカーに転送するリスナーを登録します。これらのメッセージは、次にbackground/messagesの下に登録された適切なメッセージフローハンドラーによって処理されます。

sendToBackgroundViaRelay関数は、リレーを介してメッセージを送信し、応答を待ちます。適切な処理と応答の追跡を確保するために、各メッセージに一意のインスタンスIDを生成します。

これらの関数の実装は、GitHubリポジトリ (opens in a new tab)で確認できます。

この方法は、Chrome拡張機能のドキュメントで説明されている"externally_connectable" (opens in a new tab)メソッドの代替手段を提供します。

リレーの設定

リレーを設定するには、コンテンツスクリプトでrelayMessage関数を使用します。コンテンツスクリプトには複数のリレーを含めることができます。前の例からのpingメッセージハンドラーとウェブサイトwww.plasmo.comを想定すると:

contents/plasmo.ts
import type { PlasmoCSConfig } from "plasmo"
 
import { relayMessage } from "@plasmohq/messaging"
 
export const config: PlasmoCSConfig = {
  matches: ["http://www.plasmo.com/*"] // Only relay messages from this domain
}
 
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("some message was relayed:", req)
    return {
      message: "Hello from sandbox"
    }
  }
)

ポート

⚠️

ポートメッセージングAPIはパブリックアルファプレビュー版です。バグ、不完全/漏洩した抽象化、および将来のAPIの変更を予期してください。遭遇した問題については、このリンクからお知らせください

メッセージングポートAPIは、ChromeランタイムのポートAPI (opens in a new tab)を抽象化した高レベル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: "Hello from port handler"
  })
}
 
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"
          })
        }}>
        Send Data
      </button>
    </div>
  )
}
 
export default DeltaTab

E2E 型安全性 (WIP)

エンドツーエンドのリクエスト/レスポンスボディの型安全性は、#334 (opens in a new tab)で進行中です。それまでは、提供されている汎用型を使用できます。

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: "Hello from background"
  })
}
 
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)