Vite 环境变量与 import.meta.env
说明 Vite 的 mode、.env 文件加载顺序、VITE_ 前缀与 import.meta.env 在开发/构建中的替换语义。
#concept
#growing
#frontend
#javascript
[!info] related notes
- 所属:Vite 基础 MOC
- 前置:Mode 模式 · 双路径
- 后续:开发服务器与代理
- 实战坑:Nx 与 env 冲突
Vite 环境变量与 import.meta.env
这个概念为什么出现
前端不能像服务端那样随便把密钥打进浏览器包。项目又需要:
- 开发 / 预发 / 生产 API 地址不同
- 功能开关随环境变化
- 构建期注入版本号
Vite 用 mode + .env* + import.meta.env 给出约定,而不是让业务代码直接读任意 process.env。
[!abstract] 一句话理解 只有暴露给客户端的变量(默认
VITE_前缀)会进入import.meta.env,并在构建时被静态替换;mode 决定加载哪套.env文件。
最小可运行示例
场景:库存后台在本地连 mock,预发连测试网关
# .env
VITE_APP_TITLE=库存后台
# .env.development
VITE_API_BASE_URL=http://localhost:3000
# .env.staging
VITE_API_BASE_URL=https://api.staging.example.com
// src/api/client.ts
// 业务意图:所有列表请求打到当前环境的 API 根路径。
// 教学点:只读取 VITE_ 变量;缺省时要显式处理,不能假设一定有值。
const apiBase = import.meta.env.VITE_API_BASE_URL
export async function fetchLowStockItems() {
if (!apiBase) {
// 失败路径:配置缺失应尽早暴露,避免请求打到相对路径的错误服务
throw new Error('VITE_API_BASE_URL is not defined')
}
const response = await fetch(`${apiBase}/inventory/low-stock`)
if (!response.ok) {
throw new Error(`low-stock request failed: ${response.status}`)
}
return response.json()
}
// 教学点:MODE/DEV/PROD 是内置键
export function envBanner() {
return `${import.meta.env.VITE_APP_TITLE} @ ${import.meta.env.MODE}`
}
建议运行:
pnpm dev # mode=development,加载 .env + .env.development
pnpm build --mode staging
pnpm preview
期望:
dev 横幅类似:库存后台 @ development
staging 构建后 API 指向测试网关;
未通过其他途径注入的非 VITE_ 变量不会自动暴露给客户端;这不保证整个源码或产物绝无密钥。
结合场景再看三个关注点
- 前缀是公开配置的筛选规则,不是秘密保护机制;带 VITE_ 的值都应视为公开。
- mode 选文件,
NODE_ENV不承担全部环境命名。 - 构建期替换:不要指望改服务器 env 文件就能改已构建的静态包。
核心规则
- 加载顺序(同名后者覆盖,细节以官方为准):
.env→.env.local→.env.[mode]→.env.[mode].local;进程启动时已有的环境变量优先级最高 - 客户端暴露:默认仅
VITE_*(可用envPrefix配置,但更要谨慎) - 内置:
MODE、BASE_URL、PROD、DEV、SSR - 自定义变量是字符串:
"false"仍为真值,应显式比较=== 'true';数值需转换并验证 - TypeScript:在包含
vite/client类型的项目中扩展ImportMetaEnv;声明类型不会检查运行时 env 是否存在 - Vite 配置求值时不会自动把
.env*全部放进process.env;需按 mode 调用loadEnv,不要将加载结果整体注入客户端
边界与反直觉
- 未定义的
import.meta.env.VITE_X为undefined,不自动抛错 .local文件通常不入库,避免把个人密钥提交- 服务端密钥应放在 BFF/网关,不要
VITE_暴露
常见误区
[!warning] 常见误区:把 mode 当成 NODE_ENV 的别名
staging可以是自定义 mode;生产构建时NODE_ENV仍可能是 production。以官方 mode 文档为准。
工程实践
- API 根路径、Sentry DSN 等“本来就要进前端”的配置才用
VITE_ - CI 用
--mode选择环境,而不是手工改文件 - monorepo 注意工具链重复加载 env 的冲突(见既有 debug 笔记)
本节总结
环境变量系统是 Vite 工程化的开关面板:mode 选文件,VITE_ 控暴露,import.meta.env 在构建时落地。
自测题
- 数据库密码能否放进
.env.production并以VITE_读取? - 为什么改
.env后有时要重启 dev server?
参考答案
- 不能;会打进前端包,等于公开。
- env 在服务启动时加载;多数改动不会热更新进已运行进程。
延伸阅读
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Env Variables and Modes | 官方 | 加载与前缀规则 |