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

EXTENSION_PUBLIC_* 值的新标签页扩展,看看环境变量是如何工作的。
content-env

工作原理
扩展产物(编译时)
构建扩展时,编译器会按以下顺序在扩展包目录中选择一份与之匹配的 env 文件:.env.[browser].[mode](例如.env.chrome.development).env.[browser]- 上述两项的引擎家族变体(见下方说明)
.env.[mode].env.local.env
chromium、chrome、edge、chromium-based、各 Chromium 分支以及 Safari 构建)还会依次尝试 .env.chromium、.env.chrome、.env.edge 与 .env.chromium-based(各自的 .[mode] 变体优先)。Gecko 家族目标还会尝试 .env.firefox 与 .env.gecko-based。因此一份 .env.chromium 文件即可覆盖 chrome、edge 或 brave 构建,而精确的浏览器文件总是优先于家族文件。
如果存在 .env.defaults,Extension.js 总是先合并它,然后再合并所选文件的变量。最终,系统 process.env 对重叠的键拥有最高优先级。
选择的是上述列表中的单个 env 文件(加上
.env.defaults),而不是对所有文件做完整级联。.env.example
仅作为文档示例,永远不会作为值来源被加载。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,以便配置可以读取它们:
.env.defaults(存在时合并)- 然后是以下文件中首个存在的那个:
.env.development、.env.local、.env
.env.chrome 或 .env.chrome.development。需要时,请通过 shell 或持续集成 (CI) 流水线中的普通 process.env 设置。
你也可以依赖编译期的产物 env(上文已说明) 将 EXTENSION_PUBLIC_* 注入扩展代码。
Workspace 回退: 如果扩展包目录中找不到上述任何文件,则会在最近的、包含 pnpm-workspace.yaml 的目录中执行同样的预加载(约束与上文一致)。
之所以分成两条路径,是因为读取配置文件时与浏览器无关,而打包器知道当前的浏览器与模式。
内置环境变量
Extension.js 在编译时注入内置变量,因此你总能在扩展代码里拿到当前的浏览器与模式。
上述所有内置变量同时可通过
process.env.* 与 import.meta.env.* 读取。
环境变量清单
公开/运行时变量(用户定义)
静态占位符变量
内置/别名变量
CLI 与开发服务器运行控制变量
遥测控制变量
完整退出契约请参见遥测与隐私。
浏览器传输调优变量
这些变量会覆盖内部 Chrome DevTools Protocol (CDP) 与 Remote Debugging Protocol (RDP) 的超时设置。它们对慢速持续集成 (CI) 环境、Docker 容器或调试不稳定的浏览器连接很有用。浏览器特定的环境变量
以下规则适用于编译期/产物 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]- 引擎家族变体(例如任何 Chromium 家族目标都会匹配
.env.chromium) .env.[mode].env.local.env
.env.chromium 即可覆盖 chrome、edge 及各 Chromium 分支,.env.firefox 覆盖各 Gecko 分支。只有当某个目标需要与家族其他成员不同的值时,才添加精确的浏览器文件(例如 .env.edge)。
示例文件
自定义环境变量
你可以在项目根目录的 env 文件中定义自定义变量。Extension.js 只会把以
EXTENSION_PUBLIC_ 为前缀的变量注入 JavaScript 产物(process.env / import.meta.env)。
EXTENSION_PUBLIC_ 前缀的变量注入 JS 产物。但输出的
.json / .html 文件中的占位符可以解析 $EXTENSION_* 标记,所以不要在静态资产模板里引用密钥。
使用环境变量
你可以在manifest.json、locale 文件、HTML、JavaScript/TypeScript 文件中使用环境变量。
1. 在 manifest.json 中
manifest.json 本身不支持环境变量,但 Extension.js 会在构建期替换支持的占位符。例如:
$EXTENSION_PUBLIC_API_KEY 替换为解析后的 env 值。
2. 在 locale 文件中
当值应当随环境而变时,也可以在 locale 文件中使用占位符。例如:$EXTENSION_PUBLIC_SITE_URL 这样的占位符替换为解析后的值。
3. 在 HTML 文件中
也可以在静态 HTML 文件中(例如pages/ 下)使用占位符:
$EXTENSION_PUBLIC_API_KEY。
4. 在 JSX 组件中
在 React/JSX/TS 文件中,用process.env 读取 env 值:
import.meta 支持
对于 ECMAScript Module (ESM) 工作流,Extension.js 同样支持 import.meta.env:
service_worker.mjs
import.meta.env 与 process.env 是对等的。
读取任何 env 文件都未定义的键会得到 undefined,而不会崩溃:Extension.js 会把裸的 import.meta.env 定义为包含所有已注入变量的对象(与 Vite 行为一致),因此 import.meta.env.MISSING_KEY 和 const {FOO} = import.meta.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、浏览器/模式变体)。
下一步
- 在可用浏览器中查看浏览器目标。
- 在
extension.config.js中配置共享默认值。 - 通过
extension build进行发布构建。

