环境变量:.env 与内置变量
本教程共 45 篇 · 第 27 篇 · 更新于 2026-08-13 · 约 4 分钟阅读
本节目标:学会用 .env 文件管理环境变量,认识 WXT 的内置变量,并掌握在清单里引用环境变量的正确姿势。
环境变量(environment variables)用来存放「随环境变化的值」:API 地址、接口密钥、功能开关。WXT 完全复用 Vite 的 dotenv 机制,学一次,到处用。
环境变量从哪里来
在项目根目录创建 dotenv 文件,里面写 KEY=value 即可。WXT 支持下面这些文件,按需创建:
.env
.env.local
.env.[mode]
.env.[mode].local
.env.[browser]
.env.[browser].local
.env.[mode].[browser]
.env.[mode].[browser].local
其中 [mode] 是构建模式(§26),[browser] 是目标浏览器。比如 .env.production 只在生产构建生效,.env.firefox 只在构建 Firefox 版本时生效。文件名带 .local 的用于本机私有配置,一般写进 .gitignore 不提交。
文件一多,同名变量就可能撞车。优先级遵循 Vite 的约定:已经存在于进程里的环境变量最高,不会被覆盖;带模式后缀的文件优先于不带后缀的;带 .local 的优先于不带 .local 的。简单记——越具体越优先,同名的值取优先级高的一方。
前缀规则:WXT_ 或 VITE_
文件里的变量不是全部都能在代码里用。按照 Vite 的约定,只有以 WXT_ 或 VITE_ 开头的变量才会暴露给运行时:
# .env
WXT_API_KEY=your-secret-key
await fetch(`/some-api?apiKey=${import.meta.env.WXT_API_KEY}`);
Tip不带前缀的变量不会出现在
import.meta.env里,但它依然存在于进程环境中,配置类文件(比如wxt.config.ts)可以用process.env读取。区分好这两种场景即可。
另外记住:dotenv 文件里的值一律是字符串。需要布尔、数字等类型时自己转换,§26 里 app.config.ts 的写法就是干这个的。
WXT 的内置变量
除了你自己定义的变量,WXT 还根据当前命令注入一组内置变量:
| 用法 | 类型 | 说明 |
|---|---|---|
import.meta.env.MANIFEST_VERSION | 2 | 3 | 目标清单版本 |
import.meta.env.BROWSER | string | 目标浏览器 |
import.meta.env.CHROME | boolean | 等价于 BROWSER === "chrome" |
import.meta.env.FIREFOX | boolean | 等价于 BROWSER === "firefox" |
import.meta.env.SAFARI | boolean | 等价于 BROWSER === "safari" |
import.meta.env.EDGE | boolean | 等价于 BROWSER === "edge" |
import.meta.env.IS_CHROME | boolean | 等价于 BROWSER === "chrome"(测试环境也会注入,见 §36) |
import.meta.env.OPERA | boolean | 等价于 BROWSER === "opera" |
设置 targetBrowsers 配置项后,BROWSER 的类型会收窄成 "chrome" | "firefox" 这样的字面量联合,写代码时能拿到补全和校验。
Vite 自带的变量也能用:MODE(当前模式)、PROD(生产构建时为 true)、DEV(与 PROD 相反)。另外两个 Vite 变量在 WXT 里没什么用:BASE_URL 请改用 browser.runtime.getURL,SSR 永远为 false。
在清单里引用环境变量
清单里的字段经常需要环境变量,比如 OAuth 的 client_id。此时必须用函数语法:
export default defineConfig({
modules: ['@wxt-dev/module-vue'],
manifest: () => ({
oauth2: {
client_id: import.meta.env.WXT_APP_CLIENT_ID,
},
}),
});
原因在于加载顺序:WXT 要等配置文件加载完,才能把 .env 文件读进进程。如果 manifest 写成对象字面量,求值发生在 .env 加载之前,变量自然是空的;写成函数,创建清单对象的时机被推迟到 .env 加载之后。
还有一个细节:配置文件里没有 Vite 的运行时变量,比如 import.meta.env.DEV 在这里是未定义的。想判断开发模式,用函数参数 mode:
export default defineConfig({
manifest: ({ mode }) => {
const isDev = mode === 'development';
console.log('Is development mode:', isDev);
// ...
},
});
一份 .env.example 模板
真实项目的习惯是提交一份 .env.example 作为变量清单,让别人照葫芦画瓢。mkext 的模板长这样:
# Better Auth backend. Point this at your deployed backend in prod.
VITE_AUTH_URL="http://localhost:3000"
# Public Google Chrome Extension OAuth client ID.
VITE_GOOGLE_EXTENSION_CLIENT_ID=""
# Ahrefs free Domain Rating API key. This is bundled into the extension build.
VITE_AHREFS_API_KEY=""
注意最后一条注释:以 WXT_ 或 VITE_ 开头的变量都会打包进扩展产物,等于公开(WXT_ 前缀并不会「只留在构建期」,官方文档里就有在运行时代码用 WXT_API_KEY 的示例)。所以真正的密钥不要放进任何带前缀的变量——构建期才用的配置走 process.env(不进产物,见前面 TIP),运行时确实需要的公开数据(比如 API 地址)才用 WXT_/VITE_ 前缀,并接受它被公开的事实。
Warning以
WXT_或VITE_开头的变量都会进入产物代码,任何用户都能在扩展包里翻到。不要往里面放真正的服务端密钥。
小结
WXT_/VITE_前缀的变量进import.meta.env,不带前缀的走process.env(只读不打包)。- 带前缀的变量都会进产物,密钥一律别放。
- manifest 里引用环境变量必须用函数语法(
manifest: () => ({...}))。