> ## 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.

# 浏览器扩展中的环境变量

> 在 Chrome、Firefox 和 Edge 扩展中安全地使用 .env 文件和浏览器特定的环境值。把密钥从打包后的扩展代码中剔除。

让同一个扩展代码库在不同浏览器与环境间运行，而不必硬编码任何值。

## 浏览器扩展中的环境变量

浏览器扩展会发布到用户机器上运行。这让配置与密钥之间的界线比普通 Web 应用更加严格。任何安装你扩展的人都能读取你打进 JavaScript、HTML 或编译后的 `manifest.json` 中的所有内容。

Extension.js 通过两种环境加载路径来处理这件事。一种用于**编译后的扩展产物**(感知浏览器与模式)。另一种用于在 Node 中加载 **`extension.config.*`**。

两条路径都很重要，取决于你在哪里读取变量。

## 模板示例

### `new-env`

<img src="https://mintcdn.com/extensionjs/VCnDd7fX2Nza24SE/images/examples/new-env/screenshot.png?fit=max&auto=format&n=VCnDd7fX2Nza24SE&q=85&s=09a0e8719d5f38a3424622eb55b2b8c7" alt="new-env template screenshot" width="2400" height="1800" data-path="images/examples/new-env/screenshot.png" />

通过一个读取 `EXTENSION_PUBLIC_*` 值的新标签页扩展，看看环境变量是如何工作的。

<CodeGroup>
  ```bash npm theme={null}
  npx extension@latest create my-extension --template=new-env
  ```

  ```bash pnpm theme={null}
  pnpx extension@latest create my-extension --template=new-env
  ```

  ```bash yarn theme={null}
  yarn dlx extension@latest create my-extension --template=new-env
  ```

  ```bash bun theme={null}
  bunx extension@latest create my-extension --template=new-env
  ```

  ```bash bun theme={null}
  bunx extension@latest create my-extension --template=new-env
  ```
</CodeGroup>

代码仓库：[extension-js/examples/new-env](https://github.com/extension-js/examples/tree/main/examples/new-env)

### `content-env`

<img src="https://mintcdn.com/extensionjs/VCnDd7fX2Nza24SE/images/examples/content-env/screenshot.png?fit=max&auto=format&n=VCnDd7fX2Nza24SE&q=85&s=c684c36c37bf2e86d42e8bf59d9b69d9" alt="content-env template screenshot" width="2400" height="1800" data-path="images/examples/content-env/screenshot.png" />

在注入到网页中的 content script 内使用环境变量。

<CodeGroup>
  ```bash npm theme={null}
  npx extension@latest create my-extension --template=content-env
  ```

  ```bash pnpm theme={null}
  pnpx extension@latest create my-extension --template=content-env
  ```

  ```bash yarn theme={null}
  yarn dlx extension@latest create my-extension --template=content-env
  ```

  ```bash bun theme={null}
  bunx extension@latest create my-extension --template=content-env
  ```

  ```bash bun theme={null}
  bunx extension@latest create my-extension --template=content-env
  ```
</CodeGroup>

代码仓库：[extension-js/examples/content-env](https://github.com/extension-js/examples/tree/main/examples/content-env)

## 工作原理

### 扩展产物(编译时)

构建扩展时，编译器会按以下顺序在扩展包目录中**选择一份**与之匹配的 env 文件：

1. `.env.[browser].[mode]`(例如 `.env.chrome.development`)
2. `.env.[browser]`
3. `.env.[mode]`
4. `.env.local`
5. `.env`
6. `.env.example`

如果存在 `.env.defaults`，Extension.js **总是先合并**它，然后再合并所选文件的变量。最终，**系统** `process.env` 对重叠的键拥有最高优先级。

<Note>
  选择的是上述列表中的**单个** env 文件(加上 `.env.defaults`)，而不是对所有文件做完整级联。
</Note>

如果项目旁找不到匹配文件，Extension.js 会从**最近的 workspace 根目录**重复同样的搜索。所谓 workspace 根目录，是离当前位置最近、包含 `pnpm-workspace.yaml` 的祖先目录。位于 monorepo 中的扩展可以共享根级 env 文件来注入**产物**。

**Monorepo 约束：** 仅当祖先目录中存在 `pnpm-workspace.yaml` 这个标记文件时，workspace 回退才会执行。如果你使用的是仅依赖 `package.json` `"workspaces"` 字段的纯 npm 或 Yarn workspaces，则不会触发自动根目录查找。这种情况下，请把 env 文件放在扩展包旁边，或在仓库根目录加上 `pnpm-workspace.yaml`。

### `extension.config.*`(Node 中，在你的配置运行之前)

`extension.config.js` / `.mjs` / `.cjs` 在 Node 中运行。在 Extension.js 求值该文件之前，会预先把**一小组**文件加载进 `process.env`，以便配置可以读取它们：

1. `.env.defaults`(存在时合并)
2. 然后是以下文件中**首个**存在的那个：`.env.development`、`.env.local`、`.env`

这一预加载步骤**不会**使用浏览器作用域的文件，比如 `.env.chrome` 或 `.env.chrome.development`。需要时，请通过 shell 或持续集成 (CI) 流水线中的普通 `process.env` 设置。

你也可以依赖编译期的产物 env(上文已说明) 将 `EXTENSION_PUBLIC_*` 注入扩展代码。

**Workspace 回退：** 如果扩展包目录中找不到上述任何文件，则会在最近的、包含 `pnpm-workspace.yaml` 的目录中执行同样的预加载(约束与上文一致)。

之所以分成两条路径，是因为读取配置文件时与浏览器无关，而打包器知道当前的浏览器与模式。

## 内置环境变量

Extension.js 在编译时注入内置变量，因此你总能在扩展代码里拿到当前的浏览器与模式。

| 变量名                        | 说明                                               |
| -------------------------- | ------------------------------------------------ |
| `EXTENSION_PUBLIC_BROWSER` | 当前扩展的浏览器目标(例如 `chrome`、`firefox`、`edge`)。        |
| `EXTENSION_PUBLIC_MODE`    | 扩展当前运行的模式，比如 `development` 或 `production`。       |
| `EXTENSION_BROWSER`        | 浏览器目标(非 legacy 别名)。                              |
| `EXTENSION_MODE`           | 构建模式(非 legacy 别名)。                               |
| `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 毫秒后自动退出 dev 进程              | CI 中的强制停止控制                     |
| `EXTENSION_FORCE_KILL_MS`  | 强制 kill 超时兜底                  | 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`       | 将遥测载荷打印到 stderr(设为 `1`)          | 未设置     |

完整退出契约请参见[遥测与隐私](/docs/features/telemetry-and-privacy)。

### 浏览器传输调优变量

这些变量会覆盖内部 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`  |

## 浏览器特定的环境变量

以下规则适用于**编译期/产物** env 选择(见上文[扩展产物](#扩展产物编译时))。它们**不适用于** Node 中针对 `extension.config.*` 的窄范围预加载。

需要为每个浏览器使用不同的值吗？Extension.js 支持浏览器作用域的 env 文件，比如 `.env.chrome`(Chrome 扩展环境变量) 与 `.env.firefox`(Firefox 扩展环境变量)。你也可以把浏览器和模式组合起来，针对单个构建变体：

* `.env.chrome.development`：只有在以开发模式运行 Chrome 时，Extension.js 才应用它。
* `.env.firefox.production`：只有在以生产模式构建 Firefox 时，Extension.js 才应用它。

优先级顺序：

* `.env.[browser].[mode]`
* `.env.[browser]`
* `.env.[mode]`
* `.env.local`
* `.env`
* `.env.example`

### 示例文件

```ini theme={null}
# .env.chrome.development
EXTENSION_PUBLIC_API_URL=https://api-dev.chrome.com
```

```ini theme={null}
# .env.firefox.production
EXTENSION_PUBLIC_API_URL=https://api.firefox.com
```

## 自定义环境变量

你可以在项目根目录的 env 文件中定义自定义变量。\
Extension.js 只会把以 `EXTENSION_PUBLIC_` 为前缀的变量注入 JavaScript 产物(`process.env` / `import.meta.env`)。

```ini theme={null}
# .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 产物。\
但输出的 `.json` / `.html` 文件中的占位符可以解析 `$EXTENSION_*` 标记，所以不要在静态资产模板里引用密钥。

## 使用环境变量

你可以在 `manifest.json`、locale 文件、HTML、JavaScript/TypeScript 文件中使用环境变量。

### 1. 在 `manifest.json` 中

`manifest.json` 本身不支持环境变量，但 Extension.js 会在构建期替换支持的占位符。例如：

```json theme={null}
{
  "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. 在 locale 文件中

当值应当随环境而变时，也可以在 locale 文件中使用占位符。例如：

```json theme={null}
{
  "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/` 下)使用占位符：

```html theme={null}
<!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 值：

```jsx theme={null}
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 会在编译期内联这些值，并且可以按浏览器/模式而变化。

## `import.meta` 支持

对于 ECMAScript Module (ESM) 工作流，Extension.js 同样支持 `import.meta.env`：

```js title="service_worker.mjs" theme={null}
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` 中的任意值。请把扩展包视为公开内容。

几条规则要遵守：

* 永远不要把 API 密钥、签名密钥或鉴权令牌放在 `EXTENSION_PUBLIC_*` 后面。这个前缀意味着该值可以安全发布，而不是用来隐藏它。
* 不要在静态 `manifest.json`、locale 或 HTML 模板中放敏感值对应的 `$EXTENSION_*` 占位符。它们会在构建期展开，最终出现在产物里。
* 把任何特权操作放到你自己的后端，扩展在运行时再调用它。
* 对于持续集成 (CI)，把构建期密钥放在 `process.env`(不要提交 env 文件)，并把可共享的安全默认值放在 `.env.defaults`。

## 最佳实践

* **只暴露必须发布的值：** 只给客户端安全的键加 `EXTENSION_PUBLIC_` 前缀。
* **用 `.env.defaults` 共享团队默认值：** 在保留可预测默认值的同时，允许本地/系统覆盖。
* **不要把密钥放进静态占位符：** 避免在 HTML/JSON 模板里放敏感的 `$EXTENSION_*` 标记。
* **版本控制卫生：** 提交 `.env.example`，忽略真实的 env 文件(`.env`、`.env.local`、浏览器/模式变体)。

## 下一步

* 在[可用浏览器](/docs/browsers/browsers-available)中查看浏览器目标。
* 在 [`extension.config.js`](/docs/features/extension-configuration) 中配置共享默认值。
* 通过 [`extension build`](/docs/commands/build) 进行发布构建。
