> ## Documentation Index
> Fetch the complete documentation index at: https://extension.js.org/llms.txt
> Use this file to discover all available pages before exploring further.

# 瀏覽器擴充功能的 Manifest V3 疑難排解

> 修正 Chrome 與 Firefox 中常見的 Manifest V3 問題,包含 service worker、web_accessible_resources、host_permissions 與瀏覽器專屬行為。

Manifest V3(MV3)把背景頁面換成 service worker、強化內容安全政策,並重塑了擴充功能宣告網路與主機存取的方式。多數日常痛點其實都源自同一個原因:MV3 假設背景程式碼是暫時性、由事件驅動的。Chrome 與 Firefox 在少數鍵上也有不同解讀。

本頁彙整建置 MV3 擴充功能時最常出現的問題,附上明確修法以及 Extension.js 為你處理的部分。

## Manifest V3 背景的 `service_worker` 搭配 `type: "module"`

Chromium 在 MV3 的背景採用 service worker。若要從中 import ES module,manifest 需設定 `type: "module"`:

```json theme={null}
{
  "manifest_version": 3,
  "background": {
    "service_worker": "service_worker.js",
    "type": "module"
  }
}
```

少了 `"type": "module"`,`import` 陳述句會在註冊時失敗,而且擴充功能主控台不會出現明確錯誤。加上之後,你就能在 worker 檔案中撰寫現代 ES module 語法。

當你的背景進入點使用 ES module 語法時,Extension.js 會自動設定 `type: "module"`。它也會把 `.ts`/`.tsx` worker 編譯成單一打包輸出,讓 module 解析在正式環境中仍能正常運作。

## 為什麼 `background.js` 在 Manifest V3 行為不同

在 Manifest V2 中,`background.js` 在常駐的背景頁面執行,具有 DOM。在 Chromium 上的 Manifest V3,背景則以 service worker 執行:

* 沒有 DOM。`window`、`document`、`XMLHttpRequest` 與 `localStorage` 都不存在。請改用 `fetch` 與 `chrome.storage`。
* worker **隨時可能在閒置時被終止**,並在下一次事件喚醒。不要將狀態存在 module 範圍變數中;請持久化到 `chrome.storage`。
* 允許頂層 `await`,但長時間初始化本身無法讓 worker 維持存活。
* 在檔案最上方**同步**註冊事件監聽器,不要放在 async callback 內。註冊在 async callback 內的監聽器,不會在喚醒 worker 的那次事件中觸發。

Firefox 採用非持久化的 event page,而不是 service worker。Extension.js 會把 Chromium 路由到 `service_worker`、Firefox 路由到 `scripts`,共用同一份原始碼,使同一個背景進入點能依目標正確編譯。

## Manifest V3 的 `web_accessible_resources`

Manifest V3 把 `web_accessible_resources` 從扁平字串陣列改為 `{ resources, matches }` 區塊清單:

```json theme={null}
{
  "web_accessible_resources": [
    {
      "resources": ["images/logo.png", "pages/injected.html"],
      "matches": ["https://example.com/*"]
    }
  ]
}
```

常見錯誤:

* 列出不在建置輸出裡的路徑。Extension.js 只會輸出被 `manifest.json`、進入點 HTML 或被 import 程式碼引用的檔案。請把該檔案加為資產,讓它落到 `dist/<browser>`。
* 忘了 `matches`。少了它,資源不會暴露給任何來源。
* 使用 V2 風格的扁平字串。瀏覽器在 MV3 會安靜忽略這些。

完整範例(包含把擴充功能 URL 注入 content script)請見 [`web_accessible_resources` 實作](/docs/implementation-guide/web-accessible-resources)。

## `host_permissions` 與 `permissions`

Manifest V3 把主機存取從 `permissions` 陣列拆出來:

| 鍵                                                    | 控管的內容                                                             |
| ---------------------------------------------------- | ----------------------------------------------------------------- |
| `permissions`                                        | 具名 API 介面(`storage`、`tabs`、`cookies`、`scripting`、`alarms` 等)。     |
| `host_permissions`                                   | 擴充功能可以讀取或修改的 URL match 樣式(`https://*/*`、`*://api.example.com/*`)。 |
| `optional_permissions` 與 `optional_host_permissions` | 在執行期透過 `chrome.permissions.request` 請求的權限。                        |

把它們搞混的徵兆:

* 對你擁有存取權的網站呼叫 `chrome.cookies.get` 回傳空結果:該 URL 需要 `host_permissions`,光有 `cookies` 不夠。
* `chrome.scripting.executeScript` 出現 "Cannot access contents of url":請把該 URL 加入 `host_permissions`。
* 你只需要一個來源時,Web Store 卻警告使用者擁有「全站」存取權:請收斂主機樣式。

各 API 的對照請見[權限與主機權限](/docs/implementation-guide/permissions-and-host-permissions)。

## Firefox 的 `declarative_net_request`

`declarative_net_request`(DNR)是 MV3 用來取代封鎖型 `webRequest` 的方案。Firefox 支援它,但有幾項限制:

* 靜態規則資源檔(`rule_resources`)必須是有效的 JSON 陣列。Firefox 對於空或格式錯誤的規則檔比 Chrome 更嚴格。
* Chrome 支援的部分規則動作與條件在 Firefox 仍是部分支援。最新的對應表請參閱 [MDN 的 `declarativeNetRequest` 文件](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest)。
* 跨來源請求要套用 DNR 規則,必須有 `host_permissions`(或 `<all_urls>`)。

Extension.js 會在建置期驗證 DNR 資源,並輸出每個瀏覽器專屬的成品,讓 Firefox 專屬的規則檔不會跑到 Chrome 的建置中。

## Content script、worker 與擴充功能 URL

三個 MV3 容易讓人踩雷的地方:

* **Content script 無法存取頁面的 JavaScript scope。** 它們共享 DOM,但不共享 window。請用 `window.postMessage`(或指向 `web_accessible_resources` 項目的 `<script>` 標籤)與頁面程式碼溝通。
* **service worker 在安裝過程中無法可靠呼叫 `chrome.runtime.getURL`。** 請在需要 URL 的事件處理函式內延後解析。
* **擴充功能 URL 以 origin 為界。** 你擴充功能中的兩個頁面之間可以互相對話,但網頁無法從外部抓取它們,除非它們列在 `web_accessible_resources` 中。

## Extension.js 如何協助處理 Manifest V3

* 自動把背景進入點路由到 `service_worker`(Chromium)或 `scripts`(Firefox)。
* 當背景使用 ES module 語法時,自動設定 `type: "module"`。
* 在建置期針對作用中的 manifest 版本驗證 `web_accessible_resources`、`permissions` 與 `host_permissions`。
* 輸出每個瀏覽器專屬的 `dist/<browser>` 成品,讓 Chrome 與 Firefox 之間的 MV3 差異彼此隔離。
* 在 `extension dev` 期間,儲存時重新載入 content script、service worker 與 HTML 頁面。

## 下一步

* 閱讀[權限與主機權限](/docs/implementation-guide/permissions-and-host-permissions)。
* 閱讀[背景腳本](/docs/implementation-guide/background)與[Content scripts](/docs/implementation-guide/content-scripts)。
* 閱讀 [`web_accessible_resources`](/docs/implementation-guide/web-accessible-resources)。
* 建置流程請見[跨瀏覽器相容性](/docs/features/cross-browser-compatibility)。
* 加上前綴的 manifest 鍵請見[瀏覽器專屬的 manifest 欄位](/docs/features/browser-specific-fields)。
* 各[瀏覽器擴充功能框架](/docs/compare)如何處理 MV3 差異。
