前端环境变量配置指南:.env 文件详解

在现代前端工程化项目中,我们经常需要根据不同的运行环境(开发、测试、预发、生产)切换配置,比如 API 地址、密钥、调试开关等。为了避免将敏感信息或环境差异硬编码在源码中,主流脚手架都支持通过 .env 文件来管理环境变量。这套文件机制遵循 .env.[mode].[local] 的命名规则,加载时有严格的优先级和覆盖关系。下面就以 Vite (也兼容 Vue CLI、Create React App 等)为例,全面解析 .env 系列文件的用法。


一、为什么需要 .env 文件

  • 环境分离 :一个变量值在开发、生产环境下不同(例如 VITE_API_BASE 可能是 http://localhost:3000https://api.prod.com)。
  • 安全 :敏感密钥(如第三方 AppId)不进入 Git 仓库,通过本地 .local 文件或 CI 环境注入。
  • 便捷:无需手动改代码,启动/构建命令配合模式自动加载对应文件。

二、文件命名规则与模式(Mode)

环境变量文件遵循以下命名模式:

text

bash 复制代码
.env                # 所有环境都会加载的公共变量
.env.local          # 所有环境都会加载的本地私有变量(通常被 .gitignore 忽略)
.env.[mode]         # 只在特定模式下加载(如 .env.development)
.env.[mode].local   # 只在特定模式加载的本地私有变量

mode 到底是什么?

它由你运行项目时指定的 --mode 参数决定。例如:

  • vitevite dev → 默认 mode = development
  • vite build → 默认 mode = production
  • vite build --mode staging → 自定义 mode = staging

所以你可以创建 .env.staging 来存放预发布环境的变量,构建时通过 --mode staging 切换。


三、文件加载优先级

当运行一个特定 mode 的命令时,所有匹配的文件会被按顺序加载,后加载的变量会覆盖先加载的同名变量 。以 vite build --mode staging 为例,加载顺序是:

  1. .env(所有模式公共基础)
  2. .env.local(本地覆盖,被 git 忽略)
  3. .env.staging(模式特定,可提交到仓库)
  4. .env.staging.local(模式特定本地覆盖,被忽略)

优先级总结:.env.[mode].local > .env.[mode] > .env.local > .env

这样设计的好处是:

团队共享的基础配置放在 .env.env.staging 中并提交到 Git,开发者个人可以额外创建 .env.local.env.staging.local 进行本地覆写,互不干扰。


四、变量定义规则

.env 文件中,所有需要暴露给前端代码的变量必须以特定前缀开头,否则会被过滤,这是为了安全防止意外泄露服务器端变量。

  • Vite 项目 :前缀 VITE_
  • Create React App :前缀 REACT_APP_
  • Vue CLI :前缀 VUE_APP_(但也可通过配置支持其他前缀)

示例 .env.development 文件:

bash

ini 复制代码
# 仅有 VITE_ 开头的变量会被注入到客户端代码中
VITE_API_BASE=http://localhost:3000/api
VITE_APP_TITLE=My Dev App
VITE_DEBUG=true

# 这个变量不会被注入,仅在 Node 端构建时可用(在 vite.config.ts 中用 process.env.DB_HOST 读取)
DB_HOST=localhost

注意:.env 文件中的值都是字符串,如果需要布尔值或数字,需要在代码中手动转换(例如 VITE_DEBUG === 'true')。


五、在代码中使用环境变量

变量注入后,你可以在 JavaScript/TypeScript 代码中通过 import.meta.env(Vite)或 process.env(CRA / Vue CLI)来访问。

Vite 项目:

ts

arduino 复制代码
// .env.development 中定义了 VITE_API_BASE
const apiBase = import.meta.env.VITE_API_BASE; // "http://localhost:3000/api"
const isDebug = import.meta.env.VITE_DEBUG === 'true';

Create React App / Vue CLI:

js

ini 复制代码
const apiBase = process.env.REACT_APP_API_BASE;

index.html 或其他模板中同样可以使用(Vite):

html

xml 复制代码
<title>%VITE_APP_TITLE%</title>

TypeScript 项目中,可以为 import.meta.env 补充类型声明来获得智能提示:

ts

csharp 复制代码
// env.d.ts
interface ImportMetaEnv {
  readonly VITE_API_BASE: string;
  readonly VITE_APP_TITLE: string;
  readonly VITE_DEBUG?: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

六、.local 文件与 Git 忽略策略

一个推荐的最佳实践:

  • 提交.env.env.development.env.production(仅包含无敏感的公共配置)
  • 忽略.env.local*.local(包含个人密钥、数据库连接等敏感信息)

.gitignore 中添加:

text

bash 复制代码
# local env files
.env.local
.env.*.local

这样每个开发者或 CI 机器可以自由覆盖变量而不影响版本库。


七、在 vite.config.ts 中使用环境变量

有时我们需要在构建配置中使用环境变量(如根据环境切换代理目标)。Vite 配置文件可以访问所有 Node 环境变量(包括没有 VITE_ 前缀的)。但需要注意,vite.config.ts 中使用的是 process.env 或通过 Vite 的 loadEnv 工具加载。

ts

javascript 复制代码
import { defineConfig, loadEnv } from 'vite';

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '');
  // 现在 env 包含了所有 .env 文件的变量(包括 VITE_ 前缀)
  console.log(env.VITE_API_BASE);
  return {
    // 配置项...
  };
});

loadEnv 第三个参数可以指定前缀,传 '' 表示加载所有变量(仅供 Node 端使用)。


八、常见场景示例

1. 多环境 API 地址

text

ini 复制代码
.env                → VITE_API_BASE=/api
.env.development    → VITE_API_BASE=http://localhost:3000
.env.production     → VITE_API_BASE=https://api.myapp.com
.env.staging        → VITE_API_BASE=https://staging-api.myapp.com

运行 vite build --mode staging 时,最终 import.meta.env.VITE_API_BASEhttps://staging-api.myapp.com

2. 动态标题与特性开关

bash

ini 复制代码
# .env.development
VITE_APP_TITLE=Dev App
VITE_ENABLE_ANALYTICS=false

# .env.production
VITE_APP_TITLE=My App
VITE_ENABLE_ANALYTICS=true

3. 第三方密钥本地存放

bash

ini 复制代码
# .env.local (不提交)
VITE_GOOGLE_MAP_KEY=AIzaSy123456

代码读取 import.meta.env.VITE_GOOGLE_MAP_KEY 即可。


九、团队协作:如何保证拉取代码后项目可直接运行

很多开发者会担心:既然 .env.local 不提交到仓库,同事克隆代码后执行 npm run dev 缺少某些变量,项目岂不是跑不起来?

这确实是最常见的协作痛点,解决方案的核心是将变量明确区分为"公共配置"和"私密配置" ,并为团队提供清晰的指引。

1. 两类变量,两种存放策略

类型 特征 存放位置 是否提交 Git
公共配置(非敏感) API 地址、功能开关、环境标识、Mock 开关等 .env.development / .env.production ✅ 是
私密配置(敏感) 第三方密钥、个人数据库地址、内部 Token .env.local ❌ 否

2. 提交 .env.development.env.production 保障基本可运行

把项目启动所必需的、不敏感的公共配置直接写在 .env.development 中,并提交到仓库:

bash

ini 复制代码
# .env.development (提交到 Git)
VITE_API_BASE = https://dev-api.mycompany.com
VITE_APP_TITLE = 我的应用(开发环境)
VITE_ENABLE_MOCK = true

任何同事拉取代码后,只需执行 npm run dev,Vite 就会自动加载 .env.env.development 中的公共配置,项目便可以正常启动调试。

3. 提供 .env.example 模板,引导开发者创建本地私密配置

对于敏感变量(如个人测试密钥),绝对不能提交到仓库,但需要告知团队成员这些变量的用途和申请方式。最佳实践是在项目中提供一个不含真实值的示例文件 .env.example,并提交它:

bash

ini 复制代码
# .env.example (提交,仅含占位说明)
# 复制此文件为 .env.local 并填入你的个人测试密钥
VITE_GOOGLE_MAP_KEY = your_key_here
VITE_SENTRY_DSN = your_dsn_here

新成员加入项目时的启动流程变为:

  1. 克隆仓库
  2. 执行 cp .env.example .env.local
  3. 打开 .env.local,将占位值替换为自己的真实密钥(可从团队文档或管理员处获取)
  4. 运行 npm run dev,项目完整可用

这样一来,即使 .env.local 不提交,团队也能非常顺畅地协作。而且因为 .env.development 已经提供了基础公共配置,哪怕暂时未配置私密变量,核心功能通常也不会完全瘫痪。

4. 线上构建的变量管理同理

线上部署(CI/CD 环境)同样不需要 .env.local 文件,而是通过平台的环境变量设置界面(如 GitHub Secrets、Vercel Env 等)注入同名的 VITE_GOOGLE_MAP_KEY。构建时 Vite 会自动读取系统环境变量并注入代码,确保线上正常运行。


十、注意事项与陷阱

  • 变量替换在构建时发生 :前端代码中的环境变量会被静态替换为字符串字面量,因此不能像 Node 环境那样在运行时动态读取整个 import.meta.env,请确保在代码中直接使用 import.meta.env.VITE_XXX 形式。
  • 前缀过滤是硬性规则 :忘记加 VITE_ 前缀的变量不会被注入客户端代码,只可在 Node 侧访问。
  • 安全性 :所有带前缀的变量会直接打包进浏览器代码,任何人查看源码都能看见。绝对不要将服务器私钥、数据库密码等机密通过 VITE_ 变量暴露
  • 字符串类型:所有值都是字符串,需要布尔或数字时务必显式转换。

十一、总结

前端环境变量文件体系通过 .env.[mode].[local] 的层级设计,优雅地解决了环境配置与代码分离的需求。核心要点:

  1. 根据 --mode 自动加载对应文件。
  2. 遵循严格的覆盖优先级。
  3. 客户端变量必须使用固定前缀(VITE_ 等)才能访问。
  4. 利用 .local 文件保护敏感本地配置。
  5. 团队协作时,提交 .env.development / .env.production 提供公共配置,用 .env.example 引导开发者自行创建 .env.local,保证项目开箱即用。

掌握这套机制后,你可以轻松实现多环境切换,让项目的配置管理更安全、更灵活,同时保障团队协作的顺畅性。

相关推荐
hunterandroid7 小时前
Paging 3 RemoteMediator 实战:构建离线优先的分页列表
android·前端
Underwood_177 小时前
星级评价——了解useState
前端
hunterandroid7 小时前
[鸿蒙从零到一] ArkUI 组件化实战:构建可复用、可组合的自定义组件
前端·华为·架构
一只公羊7 小时前
iPhone摄像头 在开发/调试过程中强行停止 App,导致 `AVCaptureSession` 没有被正常释放
前端
浮江雾7 小时前
Flutter第十节-----Flutter布局与组件全解析
android·开发语言·前端·学习·flutter·入门
xcLeigh8 小时前
Doubao-Seed-Evolving大模型接入教程|搭建全品类提示词+AI工具导航网页
前端·人工智能·python·ai·html·ai开发·豆包
巴勒个啦9 小时前
Vue 3.6 Vapor Mode 实战:我把一个 Vue3 项目的渲染性能提升了 4 倍
前端·angular.js
不简说9 小时前
# JS 代码技巧 vol.7 — 20 个浏览器 API 实战,自带 API 能干的事别自己封装
前端·javascript·面试