Skip to main content
瀏覽器擴充功能有三種方式在網頁裡執行程式碼。manifest 的 content_scripts 項目會在每個符合樣式的頁面上執行。chrome.scripting.executeScript 會在你呼叫時於一個分頁裡執行一次腳本。chrome.scripting.registerContentScripts 會在執行階段註冊一個 content script,並讓它保持註冊狀態。本頁說明每種方式何時執行、需要什麼權限,以及各瀏覽器的差異。它也列出注入失敗時主控台會印出的行,以及檔案在 Extension.js 專案中該放在哪裡。

在頁面裡執行程式碼的三種方式

manifest content_scriptsmanifest.json 中的靜態宣告。瀏覽器會把列出的 jscss 檔案注入到每個符合 matches 的頁面,時機由 run_at 決定。Extension.js 會編譯每個項目並為 HMR 包裝它,請見 Content script chrome.scripting.executeScript 從 service worker 或另一個擴充功能頁面發起的一次性呼叫。它針對一個分頁,執行 files(擴充功能內的路徑)或 func(序列化到頁面裡的函式,可帶 args)。它需要 scripting 權限,外加對該分頁的存取權:來自使用者手勢之後的 activeTab,或來自相符的 host_permissions 樣式。 chrome.scripting.registerContentScripts 一種動態註冊,形狀與 manifest 項目相同(idmatchesjscssrunAtworld)。瀏覽器從那一刻起把它注入到相符的頁面,而且註冊預設會在瀏覽器重新啟動後保留。它需要 scripting 權限以及涵蓋 matcheshost_permissions,因為 activeTab 不適用於未來的頁面。 當功能屬於一組已知網站時,使用 manifest 項目。當使用者觸發功能時,例如點擊工具列按鈕,使用 executeScript。當網站集合要在執行階段才決定時,例如來自設定頁,使用 registerContentScripts

Manifest 片段

scripting 權限同時解鎖兩個執行階段 API。activeTab 涵蓋使用者點擊的那個分頁,host_permissions 涵蓋每個相符的頁面,而動態註冊需要後者:
Chromium 與 Firefox 都按原樣讀取這個區塊,所以它不需要瀏覽器前綴。只有在 manifest content script 上使用 world: "MAIN" 時才用前綴,因為 Firefox 會忽略該欄位。把它宣告為 chromium:world 並保留一個 isolated world 後備,寫法請見瀏覽器專屬欄位 與這份 manifest 對應的執行階段呼叫:

各瀏覽器差異

在 Safari 上,只啟用擴充功能並不夠。在你授予網站存取權之前,沒有任何 content script 會執行,執行階段注入的腳本也一樣。啟用與授權步驟請見 Safari

你會看到的主控台輸出

把你看到的那一行複製到搜尋裡。每一行對應一個原因。 Cannot access contents of url "https://example.com/". Extension manifest must request permission to access this host. 該分頁不在你的 host 權限之內,而且 activeTab 沒有為它授予。把該 host 加入 host_permissions,或是在分頁上發生使用者手勢之後的處理函式裡呼叫 executeScript Could not load file: 'scripts/highlight.ts'. executeScriptregisterContentScripts 呼叫寫的是原始檔路徑。Extension.js 會把 scripts/highlight.ts 編譯為 scripts/highlight.js,所以請注入產出的 .js 路徑。 Failed to load resource: net::ERR_FILE_NOT_FOUND 一個以 .ts 結尾的 chrome-extension:// URL(或其他從未到達 dist/ 的路徑)。修法相同:引用產出的 .js 檔案,然後確認它存在於 dist/<browser>/scripts/ 之下。 NS_ERROR_CONTENT_BLOCKED 同一個檔案遺失錯誤在 Firefox 的 moz-extension:// URL 上的表現形式。注入產出的 .js 路徑。 Cannot access a chrome:// URL 瀏覽器內建頁面不能被腳本化。在一般的 https:// 頁面上測試。 The extensions gallery cannot be scripted. Chrome Web Store 對所有擴充功能都禁止腳本化。換一個頁面測試。 This page cannot be scripted due to an ExtensionsSettings policy. 受管理的瀏覽器在這個 host 上封鎖了你的擴充功能。在原則允許的 host 上測試,或是換一個不受該原則管理的設定檔。

Extension.js 的做法

把執行階段注入的檔案放進 scripts/ 特殊資料夾。規則很短:
  • scripts/ 位於專案根目錄、和 package.json 並排,而不是在 src/ 裡。巢狀的 src/scripts/ 只是普通資料夾。
  • 那裡的每個檔案都會編譯成 .js,並落在 dist/<browser>/scripts/<name>.js
  • filesjs 陣列裡引用產出的路徑。.ts 路徑能正常建置,但在瀏覽器裡會 404。
  • 當執行階段字面值寫的是 .ts 原始檔時,建置會印出一則警告,給出應使用的產出路徑。
  • 該檔案遵循 content script 契約:export default 一個同步函式,並回傳可選的清理函式。
完整的資料夾契約請見特殊資料夾 extension dev 期間,你用 executeScriptscripts/ 注入的腳本會在編輯時被重播,因此注入的程式碼會像宣告式 content_scripts 一樣即時更新。請見重新載入與 HMR 建立一個在執行階段注入 scripts/ 項目的專案:
如果走靜態路徑,請改從 content 範本開始:

另請參閱