iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0
佛心分享-SideProject30

從零開始改善工作之 Chrome Extension: MR 通知文字小工具系列 第 19

Day 19:介紹 Message Passing(content ↔ background ↔ popup 溝通)

  • 分享至 

  • xImage
  •  

在昨天的實作中,我們使用到了 chrome.runtime.sendMessage 這個 API
今天來介紹一下!

什麼是 Message Passing

在 Chrome Extension 的架構中,不同模組(content script、background、popup)運作在不同的環境,彼此之間不能直接呼叫函式或共享變數。
這時就需要透過 Message Passing(訊息傳遞機制) 來讓它們彼此交換資料。

  • Content Script:與使用者正在瀏覽的網頁互動。
  • Background Service Worker:處理長期存在的邏輯,例如事件監聽、跨頁籤共享資料。
  • Popup:當使用者點擊擴充功能圖示時顯示的 UI。

這三者各自的環境是隔離的,無法直接共享變數,因此必須透過 message passing(訊息傳遞) 來協調。

溝通架構

[ content_script ] ⇔ [ background.js ] ⇔ [ popup.html / popup.js ]
  • Content Script:只能與 background 通訊,無法直接與 popup 溝通。
  • Popup:也必須透過 background 與 content script 交換資料。
  • Background:作為中央橋樑,接收並轉發訊息。

常見的訊息傳遞方式

1. 單次訊息傳遞 (One-time request)

適合 簡單請求-回應 的場景,例如:popup 要求 content script 傳回目前頁面的 MR 標題。

範例:popup → content script

//popup.html
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
  chrome.tabs.sendMessage(tabs[0].id, { action: "getMRTitle" }, (response) => {
    console.log("MR 標題:", response.title);
  });
});

// content-script.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === "getMRTitle") {
    const title = document.querySelector(".merge-request-title")?.innerText;
    sendResponse({ title });
  }
});

為什麼這邊可以透過 popup 要求 content script 傳回資料?

因為 Chrome 提供了 chrome.tabs.sendMessage API。
雖然程式碼是「在 popup 裡呼叫 sendMessage 傳給 content script」,
但實際上,這個 API 會繞過 background,直接幫你轉送到指定的 tab 的 content script。

也就是說:

  • 表面上看起來是 popup → content script
  • 但在內部實作,還是走了 extension 的 messaging channel

那會不會「衝突」?

不算衝突,而是 不同層次的說明:

  • 架構觀點:
    popup 與 content script 並不是平行、可自由溝通的環境,它們之間必須透過「extension 的 messaging channel」傳遞訊息。
    在大型專案裡,通常會建議「都透過 background 作為中央 hub」,避免耦合。
  • 實作觀點:
    開發小工具時,popup → content script 是允許的(透過 chrome.tabs.sendMessage),
    Chrome API 幫你省略了 background 的轉發步驟。

2. 持續連線 (Long-lived connection / Port API)

適合需要 持續交換訊息 的情境,例如 background 跟 content script 持續同步資料。
建立連線

// content-script.js
const port = chrome.runtime.connect({ name: "myChannel" });
port.postMessage({ msg: "Hello from content!" });

port.onMessage.addListener((msg) => {
  console.log("收到 background 回覆:", msg);
});

// background.js
chrome.runtime.onConnect.addListener((port) => {
  console.log("有連線建立:", port.name);

  port.onMessage.addListener((msg) => {
    console.log("來自 content 的訊息:", msg);
    port.postMessage({ reply: "Got it!" });
  });
});

3. 三方溝通範例:content ⇔ background ⇔ popup

假設我們想要:

  • content script 抓取 GitLab MR 資訊
  • background 集中管理邏輯
  • popup 顯示給使用者

流程:

  1. popup → background:詢問目前頁面的 MR 資訊
  2. background → content:轉發請求給 content script
  3. content → background:回傳頁面資訊
  4. background → popup:再把結果傳回 UI

這就是 典型的三層 Message Passing 流程。

核心重點

  • Message Passing 是 content / background / popup 溝通的唯一方式
  • 單次傳遞:sendMessage + onMessage
  • 持續通道:connect + Port
  • 設計時建議讓 background 當「中繼站」,集中管理訊息邏輯

參考來源


上一篇
Day 18:實作 ─ 支援多專案 Merge Request 的差異格式
下一篇
Day 20:三方溝通範例— content script ⇔ background ⇔ popup
系列文
從零開始改善工作之 Chrome Extension: MR 通知文字小工具22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言