跨瀏覽器、跨環境使用同一份擴充功能程式碼,不必把值寫死。
瀏覽器擴充功能中的環境變數
瀏覽器擴充功能會在使用者的機器上執行程式碼。這也讓「設定」與「機密」之間的界線比一般網頁應用更為敏感:任何安裝你擴充功能的人,都能讀出你打包到 JavaScript、HTML 或編譯後 manifest.json 中的內容。
Extension.js 用兩種環境載入路徑來處理這件事:一種服務 編譯後的擴充功能 bundle(會感知瀏覽器與模式),另一種則是在 Node 中載入 extension.config.* 時使用。
兩條路徑都重要,端視你要從哪裡讀取變數。
範本範例
new-env
透過一個新分頁擴充功能(讀取 EXTENSION_PUBLIC_* 值)實際看看環境變數如何運作。
npx extension@latest create my-extension --template=new-env
儲存庫:extension-js/examples/new-env
content-env
在注入網頁的 content script 中使用環境變數。
npx extension@latest create my-extension --template=content-env
儲存庫:extension-js/examples/content-env
運作方式
擴充功能 bundle(編譯時)
建置擴充功能時,編譯器會從你的擴充功能套件資料夾,依下列順序挑選 一個 第一個符合的 env 檔:
.env.[browser].[mode](例如 .env.chrome.development)
.env.[browser]
.env.[mode]
.env.local
.env
.env.example
當 .env.defaults 存在時,Extension.js 一定會先合併 它,再合併所選檔案的變數。最後,系統的 process.env 對重疊鍵擁有最高優先權。
選擇的是上述清單中的 單一 env 檔(再加上 .env.defaults),
不會逐檔串聯合併。
如果專案旁邊找不到符合的檔案,Extension.js 會從 最近的 workspace 根目錄 重複相同的搜尋;該根目錄是最近一個包含 pnpm-workspace.yaml 的祖先資料夾。Monorepo 中的擴充功能可以共用根層的 env 檔,用於 bundle 注入。
Monorepo 限制: workspace fallback 只有在祖先目錄存在 pnpm-workspace.yaml 標記時才會執行。如果你使用純 npm 或 Yarn workspaces,只靠 package.json 的 "workspaces" 欄位,這套自動往上找的機制就不適用。這種情況下,請把 env 檔放在擴充功能套件旁邊,或在儲存庫根目錄加上 pnpm-workspace.yaml。
extension.config.*(Node,在你的設定執行前)
extension.config.js / .mjs / .cjs 會在 Node 中執行。Extension.js 在評估該檔案前,會預先載入 一小組 檔案到 process.env,讓設定檔可以讀取:
.env.defaults(存在時會合併)
- 接著從
.env.development、.env.local、.env 中載入 第一個 存在的檔案
此預載步驟 不會 使用 .env.chrome 或 .env.chrome.development 等瀏覽器範圍的檔案。如果有需要,請透過 shell 或持續整合(CI)流水線中的 process.env 設定值。
你也可以依賴 bundle 階段的 env(上述章節說明),把 EXTENSION_PUBLIC_* 的值注入到擴充功能程式碼裡。
Workspace fallback: 如果擴充功能套件資料夾中都沒有這些檔案,相同的預載會從最近一個包含 pnpm-workspace.yaml 的資料夾執行(限制與上方相同)。
之所以分成兩條路徑,是因為設定檔載入時還不知道目前瀏覽器,但 bundler 已經知道當前的瀏覽器與模式。
內建環境變數
Extension.js 會在編譯時注入內建變數,讓你的擴充功能程式碼隨時都能取得瀏覽器與模式資訊。
| 變數名稱 | 說明 |
|---|
EXTENSION_PUBLIC_BROWSER | 目前擴充功能的瀏覽器目標(例如 chrome、firefox、edge)。 |
EXTENSION_PUBLIC_MODE | 擴充功能執行的模式,例如 development 或 production。 |
EXTENSION_BROWSER | 瀏覽器目標(非舊版的別名)。 |
EXTENSION_MODE | 建置模式(非舊版的別名)。 |
BROWSER | 簡短的瀏覽器別名。 |
MODE | 簡短的模式別名。 |
NODE_ENV | 與編譯器模式對齊的 Node 環境(development / production)。 |
以上所有內建變數,皆可透過 process.env.* 與 import.meta.env.* 取得。
環境變數總覽
公開/執行階段變數(使用者定義)
| 變數模式 | 用途 | 是否可在 JS 執行階段使用 | 備註 |
|---|
EXTENSION_PUBLIC_* | 將使用者定義的值暴露給擴充功能程式碼 | 是(process.env + import.meta.env) | 僅放可安全發佈的值 |
靜態佔位符變數
| 變數模式 | 用途 | 是否可在 JS 執行階段使用 | 備註 |
|---|
在輸出的 .html / .json 中的 $EXTENSION_* 標記 | 編譯時在靜態資產中做佔位符替換 | 不會做為 JS 變數 | 避免在靜態樣板中使用機密 |
內建/別名變數
| 變數 | 類型 | 備註 |
|---|
EXTENSION_PUBLIC_BROWSER | 內建 | 瀏覽器目標 |
EXTENSION_PUBLIC_MODE | 內建 | 建置模式 |
EXTENSION_BROWSER | 內建別名 | 瀏覽器目標 |
EXTENSION_MODE | 內建別名 | 建置模式 |
BROWSER | 內建別名 | 簡短瀏覽器名稱 |
MODE | 內建別名 | 簡短模式名稱 |
NODE_ENV | 內建 | 編譯器模式 |
CLI 與開發伺服器的操作變數
| 變數 | 用途 | 典型用法 |
|---|
EXTENSION_AUTO_EXIT_MS | 開發程序在 N 毫秒後自動結束 | CI 強制停止控制 |
EXTENSION_FORCE_KILL_MS | 強制終止逾時的備援設定 | CI 清理韌性 |
EXTENSION_VERBOSE | 在特定流程中輸出詳細診斷 | 除錯 CLI 行為 |
EXTENSION_AUTHOR_MODE | 維護者/作者診斷模式 | 內部診斷與工具 |
EXTENSION_CLI_NO_BROWSER | 從 CLI 停用瀏覽器啟動(設為 1) | 等同於 --no-browser 旗標 |
EXTENSION_DEV_NO_BROWSER | 在開發伺服器停用瀏覽器啟動 | Monorepo 監看時不需啟動瀏覽器 |
EXTENSION_NO_RELOAD | 在開發模式跳過 content-script 的重載執行階段 | 等同於 extension dev --no-reload |
EXTENSION_DEV_DRY_RUN | 跳過開發伺服器啟動(提前結束) | 為 CLI 接線做煙霧測試 |
EXT_BROWSERS_CACHE_DIR | 覆寫受管理瀏覽器快取資料夾 | 自訂 CI 快取路徑 |
遙測控制變數
| 變數 | 用途 | 預設值 |
|---|
EXTENSION_TELEMETRY_DISABLED | 完全停用遙測(設為 1) | 未設 |
EXTENSION_TELEMETRY | 向後相容的停用設定(設為 0 停用) | 未設 |
EXTENSION_TELEMETRY_SAMPLE_RATE | command_executed 的取樣率(0.0–1.0) | 0.2 |
EXTENSION_TELEMETRY_MAX_EVENTS | 每個 CLI 程序最多送出的事件數 | 3 |
EXTENSION_TELEMETRY_DEBOUNCE_MS | 相同事件元組的去重視窗(毫秒) | 60000 |
EXTENSION_TELEMETRY_TIMEOUT_MS | 遙測請求的 HTTP 逾時(毫秒) | 300 |
EXTENSION_TELEMETRY_DEBUG | 將遙測 payload 印到 stderr(設為 1) | 未設 |
完整的退出條款請參閱 遙測與隱私。
瀏覽器傳輸調校變數
這些變數會覆寫 Chrome DevTools Protocol(CDP)與 Remote Debugging Protocol(RDP)內部逾時設定。對於緩慢的持續整合(CI)環境、Docker 容器,或除錯不穩定的瀏覽器連線特別有用。
| 變數 | 用途 | 預設值 |
|---|
EXTENSION_CDP_COMMAND_TIMEOUT_MS | CDP sendCommand 逾時(毫秒) | 12000 |
EXTENSION_CDP_HTTP_TIMEOUT_MS | CDP HTTP /json 探索逾時(毫秒) | 1200 |
EXTENSION_CDP_HEARTBEAT_INTERVAL_MS | CDP WebSocket 心跳間隔(毫秒) | 30000 |
EXTENSION_RDP_EVAL_TIMEOUT_MS | Firefox RDP 評估逾時(毫秒) | 8000 |
EXTENSION_RDP_MAX_RETRIES | Firefox RDP 連線重試次數 | 150 |
EXTENSION_RDP_RETRY_INTERVAL_MS | Firefox RDP 連線重試間隔(毫秒) | 1000 |
瀏覽器專屬環境變數
下列規則適用於 編譯/bundle 時 的 env 選擇(請見上方的 擴充功能 bundle)。它們 不適用 於 Node 中那一小段 extension.config.* 的預載。
需要在不同瀏覽器使用不同的值?Extension.js 支援帶有瀏覽器範圍的 env 檔,例如 .env.chrome(Chrome 擴充功能環境變數)與 .env.firefox(Firefox 擴充功能環境變數)。你也可以結合瀏覽器與模式,對應到單一建置變體:
.env.chrome.development:僅在以 development 模式於 Chrome 執行擴充功能時套用。
.env.firefox.production:僅在以 production 模式為 Firefox 建置擴充功能時套用。
優先順序為:
.env.[browser].[mode]
.env.[browser]
.env.[mode]
.env.local
.env
.env.example
範例檔案
# .env.chrome.development
EXTENSION_PUBLIC_API_URL=https://api-dev.chrome.com
# .env.firefox.production
EXTENSION_PUBLIC_API_URL=https://api.firefox.com
自訂環境變數
你可以在專案根目錄的 env 檔中定義自訂變數。
Extension.js 只會把以 EXTENSION_PUBLIC_ 為前綴的變數注入到 JavaScript bundle(process.env / import.meta.env)。
# .env
EXTENSION_PUBLIC_API_KEY=your_api_key_here
EXTENSION_PUBLIC_SITE_URL=https://example.com
PRIVATE_KEY=abc123 # Not injected into JS bundles
重要: Extension.js 不會把沒有 EXTENSION_PUBLIC_ 前綴的變數注入 JS bundle。
不過,輸出的 .json/.html 檔中的佔位符可以解析 $EXTENSION_* 標記,所以請避免在靜態資產樣板中引用機密。
使用環境變數
你可以在 manifest.json、語系檔、HTML 與 JavaScript/TypeScript 檔案中使用環境變數。
1. 在 manifest.json 中
manifest.json 本身不支援環境變數,但 Extension.js 會在建置時替換掉受支援的佔位符。例如:
{
"name": "My Extension",
"version": "1.0",
"description": "This extension is connected to $EXTENSION_PUBLIC_API_KEY",
"background": {
"service_worker": "service_worker.js"
}
}
編譯時,Extension.js 會把 $EXTENSION_PUBLIC_API_KEY 取代為解析後的 env 值。
2. 在語系檔中
當值需要隨環境改變時,你也可以在語系檔中使用佔位符。例如:
{
"appName": {
"message": "My Extension - $EXTENSION_PUBLIC_SITE_URL"
},
"appDescription": {
"message": "Connected to API at $EXTENSION_PUBLIC_API_KEY"
}
}
當 Extension.js 輸出資產時,會把 $EXTENSION_PUBLIC_SITE_URL 等佔位符替換為解析後的值。
3. 在 HTML 檔中
你也可以在靜態 HTML 檔中使用佔位符(例如放在 pages/ 下):
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Extension</title>
</head>
<body>
<h1>Welcome to My Extension</h1>
<p>API Key: $EXTENSION_PUBLIC_API_KEY</p>
</body>
</html>
編譯時,Extension.js 會替換輸出 HTML 中的 $EXTENSION_PUBLIC_API_KEY。
4. 在 JSX 元件中
在 React/JSX/TS 檔案中,可以用 process.env 讀取 env 值:
const ApiInfo = () => {
const apiUrl = process.env.EXTENSION_PUBLIC_SITE_URL;
const apiKey = process.env.EXTENSION_PUBLIC_API_KEY;
return (
<div>
<h1>API Information</h1>
<p>URL: {apiUrl}</p>
<p>Key: {apiKey}</p>
</div>
);
};
export default ApiInfo;
Extension.js 會在編譯時將這些值內嵌進來,並可隨瀏覽器/模式變化。
針對 ECMAScript Module(ESM)工作流程,Extension.js 也支援 import.meta.env:
const apiUrl = import.meta.env.EXTENSION_PUBLIC_API_URL;
console.log(`API URL for the current environment: ${apiUrl}`);
對於已注入的 env 鍵,import.meta.env 與 process.env 內容一致。
擴充功能建置中的機密
瀏覽器擴充功能會在使用者的機器上執行。任何安裝你擴充功能的人,都可以檢視你打包進 JavaScript、HTML 或編譯後 manifest.json 的任何值。請把 bundle 視為公開內容。
幾條原則:
- 絕對不要把 API 機密、簽章金鑰或驗證權杖放在
EXTENSION_PUBLIC_* 之後。這個前綴是為了標記「可安全發佈」,不是為了「隱藏」。
- 機密值不要放進靜態
manifest.json、語系或 HTML 樣板中的 $EXTENSION_* 佔位符,因為它們會在建置時展開並寫進產物。
- 任何特權操作都應交由你自己的後端處理,再從擴充功能在執行階段呼叫它。
- 持續整合(CI)時,把建置機密放在
process.env(不要提交 env 檔),共用的安全預設值才用 .env.defaults。
最佳實務
- 只暴露必須發佈的值: 只有對使用者端安全的鍵才以
EXTENSION_PUBLIC_ 為前綴。
- 以
.env.defaults 提供共用預設: 保持團隊預設值可預期,同時允許本機/系統覆寫。
- 機密不要放進靜態佔位符: 避免在 HTML/JSON 樣板中放入機密的
$EXTENSION_* 標記。
- 版本控管乾淨: 提交
.env.example,並忽略真正的 env 檔(.env、.env.local、瀏覽器/模式變體)。
下一步