环境变量(.env 文件)是现代前端工程化中的"环境控制开关 "。结合你的技术栈(Vite + Vue 3 + TypeScript + pnpm),我为你系统拆解:它是什么、在 Vite 中怎么用、如何配合 TypeScript 做智能提示 ,以及绝对不要犯的致命错误。
1. 什么是环境变量?为什么需要它?
想象你开发了一个 App:
- 开发时 :调用测试接口
http://localhost:3000/api - 上线后 :调用正式接口
https://api.yourcompany.com/api
如果每次打包前都手动改代码里的 baseURL,既容易出错又繁琐。环境变量 就是把这些"随环境而变的值"抽离到 .env 文件中,Vite / Webpack 在打包时会根据当前模式(development / production)自动注入对应的值。
2. Vite 中的核心机制(与你之前用 Webpack 的区别)
如果你是 Vue CLI(Webpack)老用户,记住这句口诀:
Webpack 用
process.env,Vite 用import.meta.env。
在 Vite 项目中,所有环境变量 都挂在 import.meta.env 对象上。
3. 文件命名规则与加载优先级(重中之重)
在项目根目录(和 package.json 平级)创建以下文件:
| 文件名 | 作用 | 加载时机 |
|---|---|---|
.env |
通用配置(所有环境都加载) | 无论 dev 还是 build 都会加载 |
.env.development |
开发环境专用 | 运行 pnpm dev 时加载 |
.env.production |
生产环境专用 | 运行 pnpm build 时加载 |
.env.local |
本地覆盖(不提交 Git) | 本地私密配置(如账号密码),优先级最高 |
加载顺序(后面的覆盖前面的):
.env(基础).env.[mode](根据模式覆盖).env.[mode].local(本地私密覆盖,不提交 Git)
🧪 实验 :在
.env.development和.env中定义同一个变量,dev模式下以.env.development为准。
4. 如何定义变量?(一定要加 VITE_ 前缀)
在 .env.development 文件中:
# 只有以 VITE_ 开头的变量才会暴露给前端代码!!!
VITE_API_BASE_URL = 'http://localhost:3000/api'
VITE_APP_TITLE = '开发环境-我的项目'
# 不以 VITE_ 开头的变量,前端无法访问(仅在 Node 环境可用)
DB_PASSWORD = '123456' # 前端 import.meta.env 里读不到这个!
为什么要有 VITE_ 前缀?
因为 Vite 会将所有环境变量硬编码 到打包后的 JS 文件中。如果不加限制,你可能会把数据库密码、内网 IP 等敏感信息暴露给浏览器。只有以 VITE_ 开头的才安全地暴露给前端。
5. 在 Vue 组件 / TS 文件中如何使用
<script setup lang="ts">
// 直接通过 import.meta.env 读取
const apiUrl = import.meta.env.VITE_API_BASE_URL
const title = import.meta.env.VITE_APP_TITLE
console.log('当前接口地址:', apiUrl)
// 常用内置变量(Vite 自带)
console.log('当前模式:', import.meta.env.MODE) // 'development' 或 'production'
console.log('是否生产环境:', import.meta.env.PROD) // true/false
console.log('是否开发环境:', import.meta.env.DEV) // true/false
console.log('是否 SSR:', import.meta.env.SSR) // 通常为 false
</script>
<template>
<div>当前环境: {{ import.meta.env.MODE }}</div>
<div>接口地址: {{ import.meta.env.VITE_API_BASE_URL }}</div>
</template>
6. ⚠️ 重磅警告:修改环境变量必须重启服务!
.env 文件是在 Vite 服务启动时 读取的。如果你修改了 .env 文件:
- 必须手动终止服务 (
Ctrl + C) - 重新运行
pnpm dev
不像 vite.config.ts 那样支持热更新,这一点新手经常踩坑,改了半天发现没生效,以为写错了语法,其实是没重启。
7. TypeScript 智能提示(让你不背变量名)
默认情况下,你在 import.meta.env 上访问 VITE_XXX 会提示"类型不存在"。为了让 TypeScript 认识这些变量,在项目根目录的 env.d.ts(或 vite-env.d.ts)中添加类型声明:
/// <reference types="vite/client" />
interface ImportMetaEnv {
// 手动声明你定义的所有 VITE_ 变量(字符串类型)
readonly VITE_API_BASE_URL: string
readonly VITE_APP_TITLE: string
// 还可以添加更多...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
添加后,你在 .vue 或 .ts 文件中敲 import.meta.env.VITE_ 时,VSCode 会自动弹出提示,并且拼写错误会报红!
8. 在 vite.config.ts 中读取环境变量
有时你需要在配置文件中根据环境决定代理地址(Proxy)或插件行为。Vite 提供了 loadEnv 方法:
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig(({ command, mode }) => {
// 加载 .env 文件中的变量(第二个参数是根目录,第三个参数是前缀)
const env = loadEnv(mode, process.cwd(), 'VITE_')
// 在配置中读取
console.log('当前 API 地址:', env.VITE_API_BASE_URL)
return {
plugins: [vue()],
server: {
proxy: {
'/api': {
target: env.VITE_API_BASE_URL, // 动态代理
changeOrigin: true,
}
}
}
}
})
9. 常见业务场景实战
场景 1:区分接口域名(最常用)
- 开发:
http://localhost:3000 - 测试:
http://test-api.company.com - 正式:
https://api.company.com
只需在三个 .env 文件里分别定义 VITE_API_BASE_URL,代码里统一用 import.meta.env.VITE_API_BASE_URL,打包时自动切换。
场景 2:开关功能(灰度发布)
VITE_ENABLE_NEW_FEATURE = 'true' # 开发环境开新功能
VITE_ENABLE_NEW_FEATURE = 'false' # 生产环境关新功能
if (import.meta.env.VITE_ENABLE_NEW_FEATURE === 'true') {
// 加载新组件
}
场景 3:构建时注入版本号
在 package.json 中读取版本,或直接硬编码:
VITE_APP_VERSION = '1.2.3'
在页面底部显示 v1.2.3,方便测试人员确认版本。
10. Windows 11 下的坑与注意事项
- PowerShell / CMD 下设置临时变量与
.env无关,不建议在命令行设置,统一用.env文件即可。 - 换行符 :确保
.env文件使用LF(Unix 换行)而不是CRLF(Windows 换行),否则某些旧版本 Vite 可能会解析异常。VSCode 右下角可以切换。 - 值是否加引号 :
VITE_KEY=123和VITE_KEY="123"最终都会变成字符串'123',推荐不加引号,避免转义问题。
总结对比速查表
| 知识点 | 结论 |
|---|---|
| 读取方式 | import.meta.env.VITE_XXX |
| 前缀要求 | 必须 VITE_ 开头,否则前端读不到 |
| 内置变量 | MODE, DEV, PROD, BASE_URL |
| 修改后生效 | 必须重启 pnpm dev |
| TS 类型提示 | 在 env.d.ts 中扩展 ImportMetaEnv |
| 安全警告 | 不要放密钥!所有 VITE_ 变量最终会打进 JS 包,用户可见 |
现在去看你项目的根目录,如果还没有 .env.development 文件,赶紧创建一个试试!写完读取代码后,记得重启服务,看看控制台能不能打印出你定义的值。有任何卡住的地方,随时问我 😄