外观
Vue2 与 Vue3 项目 .env 文件学习文档
适合人群:需要在 Vue2、Vue3 项目中正确创建
.env文件,并在接口地址、代理、部署路径、功能开关中正确使用环境变量的学习者。学习目标:分清 Vue CLI 和 Vite 的环境变量规则,掌握
.env文件命名、加载模式、变量前缀、代码读取方式和常见实战配置。核对时间:2026-06-18。
目录
- .env 文件到底解决什么问题
- 先判断你的项目是 Vue CLI 还是 Vite
- Vue2 + Vue CLI 的 .env 正确写法
- Vue3 + Vue CLI 的 .env 正确写法
- Vue3 + Vite 的 .env 正确写法
- Vue2 + Vite 的 .env 正确写法
- 常见环境文件怎么组织
- 在接口请求中使用环境变量
- 在代理配置中使用环境变量
- 在部署路径中使用环境变量
- TypeScript 类型声明
- 安全规则:哪些变量不能放进前端 .env
- 运行时配置与构建时配置的区别
- 常见错误与排查
- 推荐实践模板
- 学习资源
1. .env 文件到底解决什么问题
.env 文件用于管理不同环境下的配置。
例如:
- 开发环境接口地址是
http://localhost:3000。 - 测试环境接口地址是
https://test-api.example.com。 - 生产环境接口地址是
https://api.example.com。
你不应该在代码里到处写死这些地址。
更好的做法是:
env
VUE_APP_API_BASE_URL=https://api.example.com或 Vite 项目中:
env
VITE_API_BASE_URL=https://api.example.com然后在代码中读取。
1.1 环境变量常用来放什么
适合放:
- API 基础地址。
- 应用标题。
- 部署基础路径。
- 是否启用某个前端功能。
- CDN 公共路径。
- 构建时版本号。
- 前端监控项目 ID。
不适合放:
- 数据库密码。
- 服务端私钥。
- 后端 token。
- 云服务 Secret。
- 支付密钥。
前端环境变量会被打进浏览器可下载的构建产物里,不是秘密保险箱。
2. 先判断你的项目是 Vue CLI 还是 Vite
Vue2/Vue3 不是判断 .env 规则的唯一标准。真正关键的是构建工具。
看 package.json。
2.1 Vue CLI 项目
json
{
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
}
}规则:
- 客户端变量必须以
VUE_APP_开头。 - 代码中通过
process.env.VUE_APP_XXX读取。 - 配置文件通常是
vue.config.js。
2.2 Vite 项目
json
{
"scripts": {
"dev": "vite",
"build": "vite build"
}
}规则:
- 客户端变量必须以
VITE_开头。 - 代码中通过
import.meta.env.VITE_XXX读取。 - 配置文件通常是
vite.config.ts。
2.3 快速对照表
| 项目类型 | 构建工具 | env 前缀 | 代码读取方式 | 配置文件 |
|---|---|---|---|---|
| Vue2 + Vue CLI | Webpack | VUE_APP_ | process.env.VUE_APP_XXX | vue.config.js |
| Vue3 + Vue CLI | Webpack | VUE_APP_ | process.env.VUE_APP_XXX | vue.config.js |
| Vue3 + Vite | Vite | VITE_ | import.meta.env.VITE_XXX | vite.config.ts |
| Vue2 + Vite | Vite | VITE_ | import.meta.env.VITE_XXX | vite.config.ts |
2.4 .env 文件的加载顺序与优先级(内部机制)
了解「用哪个前缀」还不够,还要理解「多个 .env 文件同时存在时谁说了算」。Vue CLI 和 Vite 的规则基本一致。
加载顺序(从低优先级到高优先级):
| 顺序 | 文件 | 说明 |
|---|---|---|
| 1 | .env | 所有模式都加载,放公共默认值 |
| 2 | .env.local | 所有模式都加载,本地个人配置,不进 Git |
| 3 | .env.[mode] | 只在对应 mode 下加载,如 .env.development |
| 4 | .env.[mode].local | 只在对应 mode 下加载,本地覆盖,不进 Git |
优先级规则:
- 越靠后的文件优先级越高,会覆盖前面文件里同名的变量。
- 真正的「最高优先级」是执行命令时已经存在的 shell 环境变量——
.env文件不会覆盖它们。 - mode 的确定:Vue CLI
serve默认development,build默认production;Vitedev默认development,build默认production。用--mode xxx可以切到自定义 mode,从而加载.env.xxx。
示例:同时存在下面三个文件时,VUE_APP_API_BASE_URL 最终取 .env.development.local 里的值:
env
# .env
VUE_APP_API_BASE_URL=/api
# .env.development
VUE_APP_API_BASE_URL=/dev-api
# .env.development.local
VUE_APP_API_BASE_URL=/local-api # 最终生效⚠️ 这也是
.env.local和.env.[mode].local必须写进.gitignore的原因——它们就是给个人本地覆盖用的,不该污染团队默认配置。
变量展开:Vue CLI 3.5+ 和 Vite 都内置 dotenv-expand,支持在一个变量里引用另一个变量:
env
VUE_APP_API_HOST=https://api.example.com
VUE_APP_API_BASE_URL=${VUE_APP_API_HOST}/v1展开后 VUE_APP_API_BASE_URL 的值为 https://api.example.com/v1。Vite 项目同理,把 VUE_APP_ 换成 VITE_ 即可。
3. Vue2 + Vue CLI 的 .env 正确写法
3.1 文件位置
放在项目根目录,和 package.json 同级:
text
my-vue2-app/
├── public/
├── src/
├── package.json
├── vue.config.js
├── .env
├── .env.development
└── .env.production3.2 文件示例
.env:
env
VUE_APP_TITLE=Vue2 学习系统.env.development:
env
NODE_ENV=development
VUE_APP_API_BASE_URL=/api
VUE_APP_PROXY_TARGET=http://localhost:3000
VUE_APP_PUBLIC_PATH=/.env.production:
env
NODE_ENV=production
VUE_APP_API_BASE_URL=https://api.example.com
VUE_APP_PUBLIC_PATH=/admin/3.3 在 Vue2 代码中读取
js
console.log(process.env.VUE_APP_TITLE)
console.log(process.env.VUE_APP_API_BASE_URL)封装 axios:
js
import axios from 'axios'
const request = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000,
})
export default request3.4 在 vue.config.js 中读取
js
module.exports = {
publicPath: process.env.VUE_APP_PUBLIC_PATH || '/',
devServer: {
proxy: {
'/api': {
target: process.env.VUE_APP_PROXY_TARGET,
changeOrigin: true,
pathRewrite: {
'^/api': '',
},
},
},
},
}3.5 Vue CLI 可暴露变量规则
客户端代码中可用:
NODE_ENV。BASE_URL。VUE_APP_开头的变量。
所以这个变量不会暴露给客户端:
env
API_SECRET=123456这个变量会暴露:
env
VUE_APP_API_BASE_URL=https://api.example.com4. Vue3 + Vue CLI 的 .env 正确写法
如果你的 Vue3 项目使用 Vue CLI,而不是 Vite,那么规则和 Vue2 + Vue CLI 基本一致。
判断方式还是看命令:
json
{
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
}
}4.1 文件示例
.env.development:
env
NODE_ENV=development
VUE_APP_API_BASE_URL=/api
VUE_APP_PROXY_TARGET=http://localhost:3000.env.production:
env
NODE_ENV=production
VUE_APP_API_BASE_URL=https://api.example.com4.2 在 Vue3 代码中读取
Composition API 中也一样:
ts
const apiBaseUrl = process.env.VUE_APP_API_BASE_URLaxios:
ts
import axios from 'axios'
export const request = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000,
})4.3 关键提醒
Vue3 不一定等于 Vite。
如果是 Vue3 + Vue CLI:
ts
process.env.VUE_APP_API_BASE_URL如果是 Vue3 + Vite:
ts
import.meta.env.VITE_API_BASE_URL5. Vue3 + Vite 的 .env 正确写法
Vue3 新项目现在常见组合是 Vite。
5.1 文件位置
text
my-vue3-vite-app/
├── public/
├── src/
├── package.json
├── vite.config.ts
├── .env
├── .env.development
└── .env.production5.2 文件示例
.env:
env
VITE_APP_TITLE=Vue3 Vite 学习系统.env.development:
env
VITE_API_BASE_URL=/api
VITE_PROXY_TARGET=http://localhost:3000
VITE_PUBLIC_PATH=/.env.production:
env
VITE_API_BASE_URL=https://api.example.com
VITE_PUBLIC_PATH=/admin/5.3 在 Vue3 + Vite 代码中读取
ts
console.log(import.meta.env.VITE_APP_TITLE)
console.log(import.meta.env.VITE_API_BASE_URL)axios:
ts
import axios from 'axios'
export const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
})5.4 Vite 内置变量
ts
import.meta.env.MODE
import.meta.env.BASE_URL
import.meta.env.PROD
import.meta.env.DEV
import.meta.env.SSR示例:
ts
if (import.meta.env.DEV) {
console.log('开发环境')
}5.5 在 vite.config.ts 中读取
vite.config.ts 运行在 Node.js 环境中。要读取 .env,使用 loadEnv。
ts
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), 'VITE_')
return {
base: env.VITE_PUBLIC_PATH || '/',
plugins: [vue()],
server: {
proxy: {
'/api': {
target: env.VITE_PROXY_TARGET,
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, ''),
},
},
},
}
})5.6 自定义前缀与目录:envPrefix、envDir
Vite 默认只暴露 VITE_ 前缀,但可以通过 vite.config.ts 修改:
ts
export default defineConfig({
envPrefix: ['VITE_', 'APP_'], // 同时接受 VITE_ 和 APP_ 前缀
envDir: 'env', // 把 .env 文件放到项目下的 env/ 目录,默认是根目录
})envPrefix:默认'VITE_',可以是字符串或字符串数组。改成''会暴露全部变量(不推荐,容易把秘密泄漏进客户端)。envDir:.env文件所在目录,默认是项目根目录(process.cwd())。
⚠️ 改前缀要同步改
src/vite-env.d.ts里的ImportMetaEnv类型声明,否则 TypeScript 会报错。
5.7 import.meta.env 是构建时静态替换,不是真正的对象
这是 Vite 环境变量最容易误解的一点:import.meta.env 在生产构建时会被「静态替换」成字符串字面量,而不是一个运行时可遍历的真实对象。
ts
// ✅ 可以:引用是完整的、固定的
const url = import.meta.env.VITE_API_BASE_URL
// ❌ 不可以:动态拼接 key,构建后拿不到值
const key = 'VITE_API_BASE_URL'
const url = import.meta.env[key]
// ❌ 不可以:遍历对象
Object.keys(import.meta.env)原因:构建时 Vite 会扫描源码,把 import.meta.env.VITE_API_BASE_URL 直接替换成 "https://api.example.com" 这种字面量;而 import.meta.env[key] 这种动态访问无法在构建期确定,替换不了,结果就是 undefined。
由此得到两条实践结论:
- 每个环境变量的访问都要写成完整的
import.meta.env.VITE_XXX字面量。 - 需要「运行时切换」的配置(同一份产物部署多环境)不能靠
import.meta.env,要用第 13 节讲的window.__APP_CONFIG__方案。
💡
import.meta.env.MODE、BASE_URL、PROD、DEV、SSR这 5 个内置变量同样会被静态替换(PROD/DEV/SSR替换成布尔值)。
6. Vue2 + Vite 的 .env 正确写法
有些项目会使用 Vue2 + Vite,例如老项目迁移或特殊脚手架。
只要构建工具是 Vite,规则就是 Vite 的规则。
.env.development:
env
VITE_API_BASE_URL=/api
VITE_PROXY_TARGET=http://localhost:3000代码中读取:
js
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL配置中读取:
ts
import { defineConfig, loadEnv } from 'vite'
import vue2 from '@vitejs/plugin-vue2'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), 'VITE_')
return {
plugins: [vue2()],
server: {
proxy: {
'/api': {
target: env.VITE_PROXY_TARGET,
changeOrigin: true,
},
},
},
}
})重点:
- Vue2 不一定只能用
VUE_APP_。 - 如果项目是 Vite,就用
VITE_。 - 判断标准永远先看构建工具。
7. 常见环境文件怎么组织
通用文件:
text
.env
.env.local
.env.development
.env.development.local
.env.test
.env.test.local
.env.staging
.env.staging.local
.env.production
.env.production.local7.1 .env
所有模式都会加载,适合放公共配置。
env
VITE_APP_TITLE=学习系统或 Vue CLI:
env
VUE_APP_TITLE=学习系统7.2 .env.local
所有模式都会加载,但通常不提交 Git。
适合放个人本地配置:
env
VITE_PROXY_TARGET=http://192.168.1.10:30007.3 .env.development
开发环境。
env
VITE_API_BASE_URL=/api7.4 .env.production
生产环境。
env
VITE_API_BASE_URL=https://api.example.com7.5 .env.staging
预发布或测试环境。
env
VITE_API_BASE_URL=https://staging-api.example.com构建命令:
Vite:
bash
vite build --mode stagingVue CLI:
bash
vue-cli-service build --mode stagingpackage.json:
json
{
"scripts": {
"build:dev": "vue-cli-service build --mode development",
"build:staging": "vue-cli-service build --mode staging",
"build:prod": "vue-cli-service build --mode production"
}
}Vite 项目:
json
{
"scripts": {
"build:dev": "vite build --mode development",
"build:staging": "vite build --mode staging",
"build:prod": "vite build --mode production"
}
}8. 在接口请求中使用环境变量
8.1 Vue CLI
.env.development:
env
VUE_APP_API_BASE_URL=/api.env.production:
env
VUE_APP_API_BASE_URL=https://api.example.comsrc/utils/request.js:
js
import axios from 'axios'
const request = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000,
})
export default request8.2 Vite
.env.development:
env
VITE_API_BASE_URL=/api.env.production:
env
VITE_API_BASE_URL=https://api.example.comsrc/utils/request.ts:
ts
import axios from 'axios'
export const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
})8.3 为什么开发环境常用 /api
开发环境中写:
env
VITE_API_BASE_URL=/api不是说后端真的部署在 /api,而是让请求先发给前端开发服务器,再通过代理转发给真实后端。
这样可以避免浏览器跨域问题。
9. 在代理配置中使用环境变量
9.1 Vue CLI 代理
.env.development:
env
VUE_APP_PROXY_TARGET=http://localhost:3000vue.config.js:
js
module.exports = {
devServer: {
proxy: {
'/api': {
target: process.env.VUE_APP_PROXY_TARGET,
changeOrigin: true,
pathRewrite: {
'^/api': '',
},
},
},
},
}9.2 Vite 代理
.env.development:
env
VITE_PROXY_TARGET=http://localhost:3000vite.config.ts:
ts
import { defineConfig, loadEnv } from 'vite'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), 'VITE_')
return {
server: {
proxy: {
'/api': {
target: env.VITE_PROXY_TARGET,
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, ''),
},
},
},
}
})9.3 开发代理只在开发环境生效
无论 Vue CLI 还是 Vite,开发代理都只影响本地开发服务器。
生产环境需要:
- Nginx 代理。
- 后端网关。
- 部署平台 rewrite。
- 同域后端服务。
不要把开发代理当成生产配置。
10. 在部署路径中使用环境变量
10.1 Vue CLI
.env.production:
env
VUE_APP_PUBLIC_PATH=/admin/vue.config.js:
js
module.exports = {
publicPath: process.env.VUE_APP_PUBLIC_PATH || '/',
}Vue Router:
js
const router = new VueRouter({
mode: 'history',
base: process.env.VUE_APP_PUBLIC_PATH || '/',
routes,
})10.2 Vite
.env.production:
env
VITE_PUBLIC_PATH=/admin/vite.config.ts:
ts
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), 'VITE_')
return {
base: env.VITE_PUBLIC_PATH || '/',
}
})Vue Router:
ts
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.VITE_PUBLIC_PATH || '/'),
routes,
})10.3 子路径部署要同时检查三处
如果部署到:
text
https://example.com/admin/检查:
- 构建工具 base:
publicPath或base。 - Vue Router base。
- 服务器 fallback。
Nginx 示例:
nginx
location /admin/ {
try_files $uri $uri/ /admin/index.html;
}11. TypeScript 类型声明
11.1 Vue CLI + TypeScript
可以创建类型声明文件,例如:
src/env.d.ts:
ts
declare namespace NodeJS {
interface ProcessEnv {
readonly NODE_ENV: 'development' | 'production' | 'test'
readonly BASE_URL: string
readonly VUE_APP_API_BASE_URL: string
readonly VUE_APP_TITLE: string
}
}读取:
ts
const baseURL = process.env.VUE_APP_API_BASE_URL11.2 Vite + TypeScript
src/vite-env.d.ts:
ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_BASE_URL: string
readonly VITE_APP_TITLE: string
readonly VITE_PUBLIC_PATH: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}读取:
ts
const baseURL = import.meta.env.VITE_API_BASE_URL12. 安全规则:哪些变量不能放进前端 .env
前端 .env 中的变量在构建后会进入客户端代码。
不能放:
env
VITE_DB_PASSWORD=123456
VITE_JWT_SECRET=abcdef
VUE_APP_ACCESS_KEY_SECRET=secret
VUE_APP_PRIVATE_TOKEN=token可以放:
env
VITE_API_BASE_URL=https://api.example.com
VITE_APP_TITLE=学习系统
VUE_APP_PUBLIC_PATH=/admin/判断规则:
如果这个值不能让用户知道,就不要放进前端
.env。
正确做法:
- 密钥放后端。
- 前端请求后端接口。
- 后端再使用密钥访问数据库或第三方服务。
13. 运行时配置与构建时配置的区别
Vue CLI 和 Vite 的 .env 多数属于构建时配置。
意思是:
- 构建时读取
.env.production。 - 把值写进构建产物。
- 部署后修改服务器环境变量,不会自动改变已经构建好的前端文件。
13.1 什么情况下会出问题
如果你想:
text
同一份 dist 部署到测试环境和生产环境,只靠服务器变量切换接口地址单纯 .env 不够。
因为 .env 的值已经在 build 时固定了。
13.2 运行时配置方案
可以使用 public/config.js:
js
window.__APP_CONFIG__ = {
API_BASE_URL: 'https://api.example.com',
}HTML 中引入:
html
<script src="/config.js"></script>代码中读取:
ts
const apiBaseUrl =
window.__APP_CONFIG__?.API_BASE_URL || import.meta.env.VITE_API_BASE_URLTypeScript 声明:
ts
declare global {
interface Window {
__APP_CONFIG__?: {
API_BASE_URL?: string
}
}
}
export {}这种方式适合需要“同一份构建产物,多环境部署”的场景。
14. 常见错误与排查
14.1 变量读取是 undefined
检查:
- 文件是否放在项目根目录。
- 变量前缀是否正确。
- Vue CLI 是否用
VUE_APP_。 - Vite 是否用
VITE_。 - 修改
.env后是否重启开发服务器。 - 当前命令是否加载了正确 mode。
14.2 Vue3 项目用了 process.env 报错
如果是 Vue3 + Vite:
错误:
ts
process.env.VUE_APP_API_BASE_URL正确:
ts
import.meta.env.VITE_API_BASE_URL如果是 Vue3 + Vue CLI,process.env.VUE_APP_XXX 才是对的。
14.3 Vue2 项目用了 import.meta.env 报错
如果是 Vue2 + Vue CLI:
错误:
js
import.meta.env.VITE_API_BASE_URL正确:
js
process.env.VUE_APP_API_BASE_URL如果是 Vue2 + Vite,则 import.meta.env 是正常的。
14.4 开发环境代理有效,生产环境无效
原因:
devServer.proxy和server.proxy只对开发服务器生效。
生产环境需要配置:
- Nginx。
- 网关。
- 后端服务。
- 部署平台 rewrite。
14.5 改了 .env 但页面没变化
解决:
- 停掉开发服务器。
- 重新运行
npm run serve或npm run dev。 - 如果是生产环境,重新 build。
- 清理浏览器缓存后再看。
14.6 .env.local 被提交了
.env.local 通常应该进 .gitignore。
示例:
gitignore
.env.local
.env.*.local14.7 用动态 key 访问 import.meta.env 拿不到值
错误:
ts
const key = 'VITE_API_BASE_URL'
const url = import.meta.env[key] // undefined原因见 5.7:import.meta.env 是构建时静态替换,动态访问无法被替换。
正确:
ts
const url = import.meta.env.VITE_API_BASE_URL14.8 自定义了 envPrefix 但变量还是 undefined
检查:
vite.config.ts里envPrefix是否写对。src/vite-env.d.ts的ImportMetaEnv是否补了对应字段。.env文件是否放在envDir指向的目录。
15. 推荐实践模板
15.1 Vue CLI 推荐模板
.env:
env
VUE_APP_TITLE=学习系统.env.development:
env
NODE_ENV=development
VUE_APP_API_BASE_URL=/api
VUE_APP_PROXY_TARGET=http://localhost:3000
VUE_APP_PUBLIC_PATH=/.env.staging:
env
NODE_ENV=production
VUE_APP_API_BASE_URL=https://staging-api.example.com
VUE_APP_PUBLIC_PATH=/admin/.env.production:
env
NODE_ENV=production
VUE_APP_API_BASE_URL=https://api.example.com
VUE_APP_PUBLIC_PATH=/admin/.env.example:
env
VUE_APP_TITLE=
VUE_APP_API_BASE_URL=
VUE_APP_PROXY_TARGET=
VUE_APP_PUBLIC_PATH=15.2 Vite 推荐模板
.env:
env
VITE_APP_TITLE=学习系统.env.development:
env
VITE_API_BASE_URL=/api
VITE_PROXY_TARGET=http://localhost:3000
VITE_PUBLIC_PATH=/.env.staging:
env
VITE_API_BASE_URL=https://staging-api.example.com
VITE_PUBLIC_PATH=/admin/.env.production:
env
VITE_API_BASE_URL=https://api.example.com
VITE_PUBLIC_PATH=/admin/.env.example:
env
VITE_APP_TITLE=
VITE_API_BASE_URL=
VITE_PROXY_TARGET=
VITE_PUBLIC_PATH=15.3 package.json 脚本模板
Vue CLI:
json
{
"scripts": {
"serve": "vue-cli-service serve",
"build:staging": "vue-cli-service build --mode staging",
"build:prod": "vue-cli-service build --mode production"
}
}Vite:
json
{
"scripts": {
"dev": "vite",
"build:staging": "vite build --mode staging",
"build:prod": "vite build --mode production",
"preview": "vite preview"
}
}16. 学习资源
- Vue CLI 模式和环境变量:https://cli.vuejs.org/guide/mode-and-env.html
- Vue CLI 配置参考:https://cli.vuejs.org/config/
- Vite 环境变量与模式:https://vite.dev/guide/env-and-mode
- Vite 配置参考:https://vite.dev/config/
- Vue 官方文档:https://vuejs.org/
最重要的记忆点:
- Vue CLI:
VUE_APP_+process.env。 - Vite:
VITE_+import.meta.env。 - 修改
.env后重启开发服务器。 - 前端
.env不能存秘密。 .env多数是构建时配置,不是运行时配置。