Skip to main content
用一份設定檔同時設定瀏覽器預設值、指令行為與 bundler 客製化。 跨團隊共用瀏覽器預設、指令選項與建置設定,不再重複輸入 CLI 旗標。Extension.js 會從專案根目錄讀取 extension.config.js(或 .mjs / .cjs),並套用到每個指令與 bundler。

運作方式

在專案根目錄(通常和 package.json 同層)加上 extension.config.js。 支援的檔名:
  • extension.config.js
  • extension.config.mjs
  • extension.config.cjs
頂層的鍵:

型別安全的設定

Extension.js 從 extension 套件匯出 FileConfig 型別,讓編輯器能對你的設定自動完成與型別檢查。用 JSDoc @type 標籤標註匯出——它可在 extension.config.js、.mjs 與 .cjs 中運作,且不需要建置步驟:

設定檔的環境載入

extension.config.* 在 Node 中執行,應該從 process.env.* 讀取值。
  • Extension.js 在評估 extension.config.* 之前,會依由弱到強的順序預先載入 env 檔:.env.defaults、.env、.env.local、.env.development。每個存在的檔案都會載入,而 shell 匯出的變數永遠優先。
  • 它會先檢查專案資料夾。
  • 在 monorepo 中,若 Extension.js 找不到專案本地的 .env*,會 fallback 到最近的 workspace 根目錄,也就是包含 pnpm-workspace.yaml 的資料夾。
  • 比起在設定檔中匯入 dotenv,建議優先使用內建的 env 預載。

瀏覽器設定

需要為每個目標設定不同的瀏覽器預設值?使用 browser:
支援的瀏覽器鍵包括:chrome、edge、firefox、chromium、chromium-based、gecko-based、firefox-based。 常用的瀏覽器欄位:
  • profile、persistProfile
  • preferences
  • browserFlags、excludeBrowserFlags
  • chromiumBinary、geckoBinary
  • extensions(僅載入的附屬擴充功能)

瀏覽器目標能力

指令設定

用 commands 定義每個指令的預設值:
注意事項:
  • extensions、transpilePackages 與 perfBudgets 在每個指令上都依由弱到強分層:頂層,接著是 browser.<vendor>,接著是 commands.<cmd>,最後是 CLI 旗標。
  • define 在同樣的層上逐鍵合併:頂層,接著是 browser.<vendor>,接著是 dev、start 與 build 上的 commands.<cmd>。
  • folders 從不逐鍵合併。browser.<vendor>.folders 取代頂層物件,dev、start 與 build 上的 commands.<cmd>.folders 則同時取代這兩者。
  • commands.build.browser、commands.start.browser 與 commands.preview.browser 決定這些指令的目標瀏覽器。--browser 旗標仍然優先。
  • start 指令會在內部依序執行 build 與 preview。Extension.js 會套用 commands.start 中的設定,包括 profile、browserFlags 與 startingUrl 等瀏覽器啟動選項。你也可以把建置專屬的設定放在 commands.build。

指令共用能力

build 指令能力

dev 指令能力

記錄能力

編譯期常數

使用 define 把常數內嵌進每個 bundle。Extension.js 會把每個值序列化為 JSON,所以字串、數字、布林值與一般物件都可以:
你的程式碼把 __APP_VERSION__ 當成一個裸識別字來讀取,建置會把它換成對應的值。在 TypeScript 專案裡,每個鍵還會在產生的 extension-env.d.ts 中得到一條環境宣告,所以 __APP_VERSION__ 會以 string 通過型別檢查。

特殊資料夾的位置

使用 folders 移動某個特殊資料夾,或把它關掉。路徑從專案根目錄解析:
  • 移動後的 scripts 或 pages 資料夾必須保留原名。Extension.js 不會讀取 src/injected 這樣的路徑。
  • false 會關掉這個資料夾。Extension.js 不再把其中的檔案編譯成進入點,也不再複製 public 資料夾。
    • 被關掉的 scripts 資料夾裡、由你的程式碼點名的腳本(例如在 chrome.scripting.executeScript({files}) 中)仍然會發佈。Extension.js 會像編譯其他資料夾裡的腳本一樣編譯它,不加內容腳本包裝。
    • 被關掉的 public 資料夾裡的任何內容都不會發佈,/icon.png 這樣的根路徑也不再指向那裡。如果 manifest 仍然點名那裡的檔案,建置會失敗並逐一列出這些檔案。如果頁面或樣式表參照了那裡的檔案,建置會為每處參照印出一則警告。請重新開啟這個資料夾,或把檔案移出 public/。
  • 移動後的資料夾與預設資料夾的行為完全一致。移動後的 scripts 資料夾裡的腳本會得到內容腳本包裝,並在 dev 中原地重新載入。移動後的 pages 資料夾裡的頁面會建置到同樣的 pages/ 輸出。頁面、樣式表或 manifest 用同樣的根路徑(例如 /logo.png)就能存取移動後的 public 資料夾裡的檔案。
  • 當 public 指定了路徑時,Extension.js 只從那個資料夾複製。
  • browser.<vendor>.folders 會整個取代頂層物件,commands.<cmd>.folders 則同時取代這兩者。兩者都不會逐鍵合併。

Rspack 設定

需要進階的 bundler 客製化?使用 config 來修補產生出的 Rspack 設定。這個範例需要 4.1.31 之後的版本:在那之前,config 裡的 config.module.rules 是 undefined,而 configResolved 才是能看到規則的 hook:
config 也可以是物件,Extension.js 會把它合併到產生出的設定之上。 config 在 Extension.js 掛上它的 loader 規則之前執行。要讀取或修改最終的設定,請使用 configResolved。它在每次 dev、build 或 start 執行中只跑一次,就在第一次編譯之前,並收到已掛上所有 loader 規則的 Rspack 設定:
這個 hook 可以修改 module、resolve、resolveLoader、node、optimization.minimize、optimization.minimizer,以及 Rspack 在建置開始時才讀取的 output 選項,例如檔案名稱與 environment。可以就地修改它們,也可以回傳一個新的設定物件。這個 hook 可以是非同步的,什麼都不回傳的 hook 會讓設定維持原樣。 到這時 Rspack 已經消耗了其餘所有鍵。這包括 entry、plugins、context、mode、target、devtool、externals、experiments 與 performance 這類鍵,minimize 與 minimizer 之外的所有 optimization 鍵,以及這些 output 鍵:path、module、library、enabledLibraryTypes、chunkFormat、chunkLoading、enabledChunkLoadingTypes、wasmLoading、enabledWasmLoadingTypes、workerChunkLoading、workerWasmLoading、workerPublicPath、pathinfo、sourceMapFilename、devtoolModuleFilenameTemplate、devtoolFallbackModuleFilenameTemplate、devtoolNamespace、bundlerInfo。對其中任何一個的修改,包括深入到值內部的修改,Extension.js 都會復原,並印出一則依路徑列出每個鍵的警告。請在 config 裡設定它們。

hook 上下文

兩個 hook 都會收到第二個引數,用來說明本次執行。它帶有 browser(目標瀏覽器,與 --browser 的寫法一致)、mode(development、production 或 none)和 command(dev、build、start 或 preview)。用它為某一個瀏覽器修改 bundler,而不必讀取 process.argv。下面的範例讓 Firefox 的商店建置保持可讀,方便審核:
extension 套件為這個引數匯出了 ConfigHookContext 型別。只接收一個引數的 hook 仍然可以正常運作。

為某一個瀏覽器保留一組 locale

商店接受的語言可能少於你的 _locales 資料夾所包含的語言。Extension.js 會為每個瀏覽器複製整個資料夾。要為某一個瀏覽器只發布其中一部分,請從 config 推入一個外掛,刪除其他 locale 的資源:
有了這個檔案,extension build --browser=edge 只會發布 _locales/en 與 _locales/de。其他所有瀏覽器仍保留整個資料夾。過濾器必須保留 default_locale 所指的資料夾。當它刪除了那個資料夾時,建置會失敗,並在錯誤中指出該 locale。

完整範例

最佳實務

  • 瀏覽器專屬值放在 browser:讓指令定義專注於工作流程,而非瀏覽器內部細節。
  • 有意識地使用頂層預設:把共用的 extensions / transpilePackages 放在根層,只在需要的地方覆寫。
  • 優先使用 chromiumBinary/geckoBinary 名稱:它們與當前的指令與型別介面一致。
  • config hook 保持最小:只補上 Extension.js 一級選項尚未涵蓋的部分。

下一步