iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0
佛心分享-SideProject30

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

Day 21:模組化訊息管理:訊息路由 utility ─ messageHandler.js

  • 分享至 

  • xImage
  •  

昨天的延伸設計有提到可以建立一個 訊息路由器 (message router),集中管理不同 action。
這個做法有點類似前端框架中 store 的感覺,以下的方法如果專案成長得更大時,可以試試看~

messageHandler.js (統一訊息路由)

// messageHandler.js

/**
 * 註冊訊息處理器
 * @param {Object} handlers - key 為 action,value 為處理函式
 */
export function registerMessageHandlers(handlers) {
  chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    const { action, data } = message;

    if (handlers[action]) {
      // 支援同步或非同步處理
      const result = handlers[action](data, sender);

      if (result instanceof Promise) {
        result.then(sendResponse).catch((err) => {
          console.error("Message Handler Error:", err);
          sendResponse({ error: err.message });
        });
        return true; // 啟用 async sendResponse
      } else {
        sendResponse(result);
      }
    }
  });
}

/**
 * 傳送訊息給 background
 */
export function sendToBackground(action, data) {
  return new Promise((resolve, reject) => {
    chrome.runtime.sendMessage({ action, data }, (response) => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError);
      } else {
        resolve(response);
      }
    });
  });
}

/**
 * 傳送訊息給指定 tab (通常用於 content_script)
 */
export function sendToTab(tabId, action, data) {
  return new Promise((resolve, reject) => {
    chrome.tabs.sendMessage(tabId, { action, data }, (response) => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError);
      } else {
        resolve(response);
      }
    });
  });
}

範例用法

Background

// background.js
import { registerMessageHandlers, sendToTab } from "./messageHandler.js";

registerMessageHandlers({
  FETCH_KEY: async (_, sender) => {
    const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
    return sendToTab(tab.id, "GET_PROJECT_KEY");
  },
});

Content Script

// content_script.js
import { registerMessageHandlers } from "./messageHandler.js";

registerMessageHandlers({
  GET_PROJECT_KEY: () => {
    const url = window.location.href;
    const match = url.match(/\/([^/]+)\/-\/merge_requests/);
    return { projectKey: match ? match[1] : "未知專案" };
  },
});

Popup

// popup.html
import { sendToBackground } from "./messageHandler.js";

document.getElementById("getKeyBtn").addEventListener("click", async () => {
  try {
    const resp = await sendToBackground("FETCH_KEY");
    document.getElementById("output").innerText = resp.projectKey;
  } catch (err) {
    document.getElementById("output").innerText = "錯誤:" + err.message;
  }
});

優點

  • 集中管理: 所有訊息邏輯透過 registerMessageHandlers,避免 onMessage 到處散落。
  • 支援非同步/同步: 你可以直接 return await fetch(...),不用自己處理 callback。
  • 易於擴充: 新增 action 只要在 handler 裡加一個 key。

上一篇
Day 20:三方溝通範例— content script ⇔ background ⇔ popup
下一篇
Day 22:介紹 Tabs API(控制瀏覽器分頁)
系列文
從零開始改善工作之 Chrome Extension: MR 通知文字小工具22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言