3、Vite 环境配置:.env 文件与 import.meta.env 实战
好,咱们接着聊 Vite 的环境配置。说实话,这块内容我当年刚接触时也踩过不少坑。Vite 内置了一套非常优雅的环境变量机制,用起来比 Webpack 那套 DefinePlugin 顺手多了。你想想看,开发环境和生产环境往往需要不同的 API 地址、不同的日志级别,甚至不同的 CDN 路径。Vite 怎么帮我们搞定这些?核心就是两个东西:.env.development 和 .env.production 文件,以及 import.meta.env 这个全局对象。
3.1 环境文件命名规则
Vite 的环境文件命名是有讲究的。它遵循一套固定的模式:
.env # 所有环境都会加载
.env.local # 所有环境都会加载,但会被 git 忽略
.env.[mode] # 只在指定模式下加载
.env.[mode].local # 只在指定模式下加载,且被 git 忽略
我个人习惯在项目根目录下创建三个文件:
.env—— 放所有环境通用的变量,比如应用名称、版本号.env.development—— 开发环境专用,比如本地 API 地址.env.production—— 生产环境专用,比如线上 API 地址
.env.local 和 *.local 文件加到 .gitignore 里。这些文件通常放敏感信息,比如数据库密码、第三方密钥。我曾经见过有人把生产环境的密钥提交到 GitHub 上,那场面……嗯,你懂的。
3.2 环境变量的定义规则
Vite 对环境变量的命名有严格要求。不是随便写个变量就能用的。记住这个规则:
只有以 VITE_ 开头的变量才会暴露给前端代码。
举个例子,你在 .env.development 里这样写:
# 这个变量可以被前端访问
VITE_API_BASE_URL = http://localhost:3000/api
# 这个变量不会被暴露
SECRET_KEY = my-secret-key
# 这个也不会
DB_PASSWORD = 123456
为什么会这样?说白了,Vite 做了安全隔离。所有暴露给前端的变量,最终都会被打包进 JS 文件里。如果你不小心把后端密钥写进去了,那等于把密码贴在了大街上。Vite 用 VITE_ 前缀强制你思考:这个变量真的应该暴露给浏览器吗?
3.3 使用 import.meta.env
定义好环境变量后,怎么在代码里读取它们?答案是 import.meta.env。这是 Vite 注入的一个全局对象,你可以在任何 JS/TS 文件里直接使用。
// 读取环境变量
const apiUrl = import.meta.env.VITE_API_BASE_URL
console.log('当前 API 地址:', apiUrl)
// 判断当前模式
if (import.meta.env.DEV) {
console.log('开发模式,开启调试工具')
}
if (import.meta.env.PROD) {
console.log('生产模式,关闭调试日志')
}
除了你自定义的 VITE_* 变量,import.meta.env 还内置了几个常用属性:
| 属性名 | 类型 | 说明 |
|---|---|---|
MODE |
string | 当前运行模式,比如 development 或 production |
BASE_URL |
string | 应用部署的基础路径,对应 base 配置项 |
PROD |
boolean | 是否为生产环境 |
DEV |
boolean | 是否为开发环境 |
SSR |
boolean | 是否在服务端渲染中运行 |
import.meta.env 在构建时会被静态替换。也就是说,你不能动态访问它,比如 import.meta.env[someVariable] 这种写法是不行的。Vite 会在编译阶段直接把这些引用替换成具体的值。
3.4 实际项目中的配置示例
好了,理论说完了,咱们看一个真实项目的配置。我在做某个中后台系统时,是这样组织的:
第一步:创建环境文件
.env —— 通用配置:
VITE_APP_TITLE = 蓝海管理系统
VITE_APP_VERSION = 1.0.0
.env.development —— 开发环境:
VITE_API_BASE_URL = http://localhost:8080/api
VITE_MOCK_ENABLED = true
VITE_LOG_LEVEL = debug
.env.production —— 生产环境:
VITE_API_BASE_URL = https://api.example.com
VITE_MOCK_ENABLED = false
VITE_LOG_LEVEL = error
第二步:在代码中使用
// src/config/index.ts
export const appConfig = {
title: import.meta.env.VITE_APP_TITLE,
version: import.meta.env.VITE_APP_VERSION,
apiBaseUrl: import.meta.env.VITE_API_BASE_URL,
isMockEnabled: import.meta.env.VITE_MOCK_ENABLED === 'true',
logLevel: import.meta.env.VITE_LOG_LEVEL,
}
// src/utils/logger.ts
const logLevels = ['debug', 'info', 'warn', 'error']
export function logger(message: string, level: string = 'info') {
const currentLevelIndex = logLevels.indexOf(appConfig.logLevel)
const messageLevelIndex = logLevels.indexOf(level)
if (messageLevelIndex >= currentLevelIndex) {
console[level](`[${appConfig.title}] ${message}`)
}
}
第三步:在 package.json 中配置启动命令
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
你看,Vite 默认会读取 .env.development 作为开发环境配置,读取 .env.production 作为生产环境配置。你不需要手动指定 --mode 参数,除非你想用自定义模式。
3.5 自定义模式
说到自定义模式,我记得有一次项目需要做「预发布环境」的测试。这时候光靠 development 和 production 就不够了。Vite 允许你创建任意模式:
创建一个 .env.staging 文件:
VITE_API_BASE_URL = https://staging-api.example.com
VITE_LOG_LEVEL = warn
然后在 package.json 里加一条命令:
{
"scripts": {
"build:staging": "vite build --mode staging"
}
}
运行 npm run build:staging 时,Vite 就会加载 .env.staging 里的变量。这个技巧我在多个项目里都用过,非常实用。
3.6 类型安全
最后聊一个进阶话题。如果你用 TypeScript,直接写 import.meta.env.VITE_API_BASE_URL 会报类型错误。因为 TypeScript 不知道这些变量存在。解决方案是在 src 目录下创建一个 env.d.ts 文件:
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_BASE_URL: string
readonly VITE_APP_TITLE: string
readonly VITE_APP_VERSION: string
readonly VITE_MOCK_ENABLED: string
readonly VITE_LOG_LEVEL: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
这样 TypeScript 就能正确推断类型了,写代码时还能有智能提示。嗯,这个细节很多人会忽略,但我觉得挺重要的。
VITE_MOCK_ENABLED 的值设成了 true(字符串),然后在代码里用 if (import.meta.env.VITE_MOCK_ENABLED) 判断。结果发现生产环境也走了 mock 逻辑。为什么?因为字符串 'true' 在 JS 里是 truthy 值。正确的做法是显式比较:=== 'true',或者用 JSON.parse 转换。
好了,Vite 的环境配置就聊到这里。说白了就是三件事:定义好 .env 文件、用 VITE_ 前缀、通过 import.meta.env 读取。下一章咱们聊聊多环境发布流程,到时候这些配置就会派上大用场了。