Skip to main content
不必為每個瀏覽器各自維護一份 manifest 檔案。 Extension.js 讓你用前綴在同一份檔案內定義瀏覽器專屬的值,在編譯時只輸出符合當前目標的欄位。

為什麼這很重要

瀏覽器在 manifest 的關鍵領域仍有差異,例如背景設定與廠商相關的中繼資料。透過帶前綴的欄位,你可以保留一份來源 manifest.json,同時為 Chromium 家族與 Firefox 家族目標產出對應正確的輸出。

運作方式

Extension.js 會掃描 manifest 鍵值,並針對所選的瀏覽器解析帶前綴的條目。前綴要不是指定一個引擎家族,就是指定單一瀏覽器:
  • chromium: 套用到每一個 Chromium 家族目標(chromiumchromeedgechromium-based,分支 braveoperavivaldiyandex,以及 Safari 輸出)
  • chrome: 只套用到 chromeedge: 只套用到 edge
  • firefox:gecko: 套用到每一個 Gecko 家族目標(firefoxgecko-based,以及分支 waterfoxlibrewolf
當帶前綴的鍵符合當前目標時,Extension.js 會在輸出的 manifest 中將其改寫為不帶前綴的鍵。分支目標會繼承其引擎家族的前綴,因此當你以 bravewaterfox 這類分支為目標時,只帶有 chromium:/firefox: 鍵的 manifest 仍能正確解析。精確的瀏覽器名稱前綴也會符合它自己的目標(例如當你執行 --browser=brave 時的 brave:)。

適用 Chromium 系瀏覽器(Chrome、Edge…)

適用 Firefox

這讓 service_worker 只會出現在 Chromium 家族的輸出中,同時為 Firefox 輸出保留 background.scripts 支援的前綴對應表: 精確的瀏覽器名稱前綴(例如 chrome:edge:brave:waterfox:)只在你以同一個瀏覽器為目標時才會解析。它勝過所屬的家族前綴,因此為 chrome 建置時,chrome: 勝過 chromium: Safari 輸出繼承 Chromium 家族,因為轉換器接收的是 Chrome 形態的 manifest。chromium: 鍵適用於 Safari,但 chrome:edge: 鍵不適用。若只想覆寫 Safari,請使用 safari:(或 webkit:),它們優先於 chromium: 鍵。 Safari 沒有實作的鍵與權限,會從 Safari 建置中自動移除,而且從 4.1.20 起,建置會為每個被移除的鍵印出一行,說明是哪個鍵、以及為什麼被移除。content_scripts[].world 會保留,因為 Safari 從 Safari 18 起就支援它。請見 建置 Safari 擴充功能 這對任何層級的任何 manifest 欄位都有效,包含 permissionscontent_scriptsbackground

只針對一個 Chromium 廠商

chromium: 是家族前綴。chrome:edge: 各自只指定一個瀏覽器,因此一個欄位可以只發佈到一個商店,而不進入另一個商店。例如,Chrome Web Store 的 key 不能進入 Edge Add-ons 的套件:
extension build --browser=chrome 會輸出 keyextension build --browser=edge 不會包含它。 不要寫 edge:key。Edge Add-ons 會拒絕任何在 manifest 中包含 key 的套件,因此該欄位在 Edge 建置裡沒有用處。擴充功能 id 由 Partner Center 指派。從 4.1.20 起,正式模式的 Edge 建置會丟棄 key 並印出一行說明原因,開發模式的建置則會保留它,因為此時穩定的 id 有用,而且不涉及任何商店。 前綴比對的是你用 --browser 要求的瀏覽器,而不是實際啟動的執行檔。當 Extension.js 退回到另一個瀏覽器執行檔時,前綴仍依要求的目標解析。
從 Extension.js 4.1.19 起,chrome:edge: 成為精確的瀏覽器前綴。在 4.1.18 及更早的版本中,它們適用於每一個 Chromium 家族目標。如果建置丟棄了 4.1.18 會套用的 chrome:edge: 鍵,建置會印出一則點名該鍵的警告。把該鍵重新命名為 chromium: 即可保留原本的套用範圍。

優先順序:三層結構

當多個鍵設定同一個欄位時,勝出者取決於層級,而不是它在檔案中的位置:
  1. 不帶前綴的一般鍵是基礎。
  2. 家族前綴(Chromium 目標上的 chromium:,Gecko 目標上的 firefox:gecko:)會覆寫一般鍵。
  3. 精確前綴會覆寫前面兩者。精確指的是該前綴點名了確切的目標,例如為 chrome 建置時的 chrome:,或為 brave 建置時的 brave:。在 Safari 與 webkit 系目標上,safari:webkit: 兩者都算精確前綴。
原始碼順序只在同一層級內用來打破平手。看以下例子:
chrome 建置會輸出 "Chrome"chrome: 點名了確切的目標,因此位於精確層,勝過 chromium:。為 edgechromiumbrave 建置則輸出 "Family",因為 chrome: 不適用於這些目標。 只有同一層級裡有兩個前綴時才會平手,例如 waterfox 這類 Gecko 分支上的 firefox:gecko:,或 Safari 目標上的 safari:webkit:。原始碼順序較後的鍵勝出。 只要帶前綴的鍵有比對到,它一定會覆寫同名的一般鍵,無論兩者在檔案中的先後位置。

前綴在每一層都會解析

解析器會走訪整棵 manifest 樹,包含陣列。位於 content_scripts 條目內或任何巢狀物件內的帶前綴鍵,都依照與頂層鍵相同的三層規則解析。

同一個解析器也驅動進入點探索

前綴解析不只影響輸出的 JSON。同一個解析器會在 script 與 HTML 進入點探索之前執行,因此 firefox:background 腳本或帶前綴的頁面,只有在相符的目標上才會成為被編譯的進入點。

分支與 *-based 別名

家族分類會先比對一份已知分支清單,再退回到子字串檢查。chromeedgebraveoperavivaldiyandex 依名稱歸類為 Chromium 家族,其他任何包含 chromium 的名稱也一樣。firefoxwaterfoxlibrewolf 依名稱歸類為 Gecko 家族,其他任何包含 geckofirefox 的名稱也一樣。這就是 chromium-basedgecko-based 別名,以及以它們為基礎的任意 *-based 名稱,都能繼承所屬家族帶前綴鍵的原因。

帶前綴的 manifest_version 需要一個不帶前綴的備援值

chrome:edge: 是精確前綴,所以只作用於某一個廠商的 manifest_version 會讓其他所有建置都沒有這個欄位。下面這份 manifest 給了 Firefox 與 Chrome 一個版本號,卻沒有給 Edge:
沒有 manifest_version 的 manifest 任何瀏覽器都不會載入。從 4.1.21 開始,建置會用一則點名被丟棄鍵的錯誤拒絕這種情況,例如 chrome:manifest_version applies only to Chrome builds, so the edge build has no manifest_version.。到 4.1.20 為止,建置會照常寫出 manifest,瀏覽器之後才拒絕它。 請寫一個不帶前綴的 manifest_version 作為基礎值,只給例外情況加前綴:
當整個 Chromium 家族需要共用一個與一般鍵不同的值時,使用 chromium:manifest_version

最佳實務

  • 共用預設值不加前綴:把共用欄位放在一般的 manifest 鍵中,只對瀏覽器專屬的差異加上前綴。
  • 僅在行為分歧時使用前綴:當執行階段需求不同時才使用瀏覽器前綴。
  • 在持續整合(CI)中為每個目標分別建置:產生並驗證每個瀏覽器的輸出(dist/<browser>),及早抓出相容性回歸。
  • 以 MDN 驗證:在加入只支援某瀏覽器的設定前,先用 MDN Web Docs 確認支援度。

下一步