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 当前运行模式,比如 developmentproduction
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 读取。下一章咱们聊聊多环境发布流程,到时候这些配置就会派上大用场了。