跳转到主要内容
让同一个扩展代码库在不同浏览器与环境间运行,而不必硬编码任何值。

浏览器扩展中的环境变量

浏览器扩展会发布到用户机器上运行。这让配置与密钥之间的界线比普通 Web 应用更加严格。任何安装你扩展的人都能读取你打进 JavaScript、HTML 或编译后的 manifest.json 中的所有内容。 Extension.js 通过两种环境加载路径来处理这件事。一种用于编译后的扩展产物(感知浏览器与模式)。另一种用于在 Node 中加载 extension.config.* 两条路径都很重要,取决于你在哪里读取变量。

模板示例

new-env

new-env template screenshot 通过一个读取 EXTENSION_PUBLIC_* 值的新标签页扩展,看看环境变量是如何工作的。
npx extension@latest create my-extension --template=new-env
代码仓库:extension-js/examples/new-env

content-env

content-env template screenshot 在注入到网页中的 content script 内使用环境变量。
npx extension@latest create my-extension --template=content-env
代码仓库:extension-js/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 对重叠的键拥有最高优先级。
选择的是上述列表中的单个 env 文件(加上 .env.defaults),而不是对所有文件做完整级联。
如果项目旁找不到匹配文件,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当前扩展的浏览器目标(例如 chromefirefoxedge)。
EXTENSION_PUBLIC_MODE扩展当前运行的模式,比如 developmentproduction
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_MSN 毫秒后自动退出 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_RATEcommand_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)未设置
完整退出契约请参见遥测与隐私

浏览器传输调优变量

这些变量会覆盖内部 Chrome DevTools Protocol (CDP) 与 Remote Debugging Protocol (RDP) 的超时设置。它们对慢速持续集成 (CI) 环境、Docker 容器或调试不稳定的浏览器连接很有用。
变量用途默认值
EXTENSION_CDP_COMMAND_TIMEOUT_MSCDP sendCommand 超时(毫秒)12000
EXTENSION_CDP_HTTP_TIMEOUT_MSCDP HTTP /json 发现超时(毫秒)1200
EXTENSION_CDP_HEARTBEAT_INTERVAL_MSCDP WebSocket 心跳间隔(毫秒)30000
EXTENSION_RDP_EVAL_TIMEOUT_MSFirefox RDP 求值超时(毫秒)8000
EXTENSION_RDP_MAX_RETRIESFirefox RDP 连接重试次数150
EXTENSION_RDP_RETRY_INTERVAL_MSFirefox 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

示例文件

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

使用环境变量

你可以在 manifest.json、locale 文件、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. 在 locale 文件中

当值应当随环境而变时,也可以在 locale 文件中使用占位符。例如:
{
  "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 会在编译期内联这些值,并且可以按浏览器/模式而变化。

import.meta 支持

对于 ECMAScript Module (ESM) 工作流,Extension.js 同样支持 import.meta.env
service_worker.mjs
const apiUrl = import.meta.env.EXTENSION_PUBLIC_API_URL;
console.log(`API URL for the current environment: ${apiUrl}`);
对于注入的 env 键,import.meta.envprocess.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、浏览器/模式变体)。

下一步