Vite 配置详解与多环境变量管理:defineConfig 全参数实战

系统拆解 Vite 配置体系:defineConfig 与配置优先级、resolve/server/build 三大核心配置块、import.meta.env 环境变量机制、.env 文件多环境管理(development/production/staging)、以及配置类型推导与常见陷阱。

引言

Vite 的「零配置可用」是一种体验,而真正让一个项目适应不同团队、不同环境、不同部署拓扑的,是它灵活而分层的配置体系。很多人把 vite.config.ts 当成一份「抄来的样板」,遇到代理失效、环境变量注入失败、生产路径不对时只能靠猜。

本文从 defineConfig 的类型推导讲起,系统拆解 resolve / server / build 三大核心配置块,深入 import.meta.env 的注入机制与 .env 多环境管理,最后给出从配置模板到常见陷阱的完整实践。读懂本文,你将能把配置文件从「黑盒样板」变成「心中有数」。

前置:https://plumephp.com/vite-scaffold-engineering/。需要了解底层实现可配合 https://plumephp.com/frontend-vite-deep-dive/。


目录


1. defineConfig 与配置优先级

1.1 为什么用 defineConfig 包裹

defineConfig 提供类型推导:包裹后 defineConfig({}) 里的配置对象会对齐完整的 UserConfig 类型,自动补全与校验,也支持条件函数形式:

import { defineConfig } from 'vite'

// 对象形式
export default defineConfig({
  base: '/',
  plugins: [],
})

// 函数形式:可接收 mode 与 command
export default defineConfig(({ command, mode, isSsrBuild }) => {
  return {
    base: command === 'serve' ? '/' : '/app/',
  }
})

1.2 回调参数

参数类型含义
command'serve' / 'build'当前是 dev server 还是构建
modestring由 --mode 或默认值决定(development/production)
isSsrBuildboolean是否 SSR 构建

1.3 配置加载顺序

命令行选项 (--port 5173)
  └─> vite.config 中的配置
        └─> 默认值 (合并,不覆盖)

规则:命令行参数的优先级高于配置文件;配置文件高于默认值。合并是浅层合并,嵌套对象需注意覆盖行为。


2. resolve:路径解析与别名

2.1 alias 的完整用法

import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'

export default defineConfig({
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
      '~': fileURLToPath(new URL('./src', import.meta.url)),
      // 也可以指向字符串
      'utils': '/src/utils',
      // 精确匹配或子路径匹配
      'react-router-dom': 'react-router-dom/es',
    },
  },
})

2.2 alias 的匹配语义

写法匹配范围
'@': path精确匹配 @ 或以 @/... 开头
'foo$': path$ 结尾仅精确匹配 foo(不匹配 foo/bar)
find 数组正则匹配

2.3 extensions 与 mainFields

export default defineConfig({
  resolve: {
    // 默认扩展名解析顺序
    extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json'],
    // 解析 package.json 时的字段优先级(默认 browser -> module -> main)
    mainFields: ['browser', 'module', 'jsnext:main', 'jsnext'],
  },
})

3. server:开发服务器调优

3.1 基础项

export default defineConfig({
  server: {
    port: 5173,
    host: '0.0.0.0',           // 允许局域网访问
    strictPort: true,          // 端口被占用时不自动递增,直接报错
    open: true,                // 启动自动打开浏览器
    cors: true,                // 开发期跨域
  },
})

3.2 proxy:开发期代理解决跨域

export default defineConfig({
  server: {
    proxy: {
      // 将 /api 请求代理到后端
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        // 路径重写:/api/users -> /users
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
      // WebSocket 代理
      '/ws': {
        target: 'ws://localhost:3000',
        ws: true,
      },
      // 正则匹配
      '/^\/fallback/': {
        target: 'http://localhost:9090',
      },
    },
  },
})

3.3 代理的核心价值

  • 开发期免 CORS:浏览器访问同源 Vite,Vite 代发请求到后端。
  • 路径改写:统一前后端 API 前缀。
  • 支持 wss/http2:ws: true 支持 WebSocket。

4. build:生产构建配置

4.1 核心项

export default defineConfig({
  build: {
    outDir: 'dist',
    assetsDir: 'assets',        // 静态资源目录
    target: 'es2020',           // 构建目标(browserslist 语法)
    minify: 'esbuild',          // 或 'terser'
    sourcemap: true,            // 生产 sourcemap
    chunkSizeWarningLimit: 500, // chunk 大小警告阈值 (kB)
    rollupOptions: {
      output: {
        // 手动分包示例
        manualChunks: {
          'vendor-react': ['react', 'react-dom'],
          'vendor-utils': ['lodash-es'],
        },
      },
    },
  },
})

4.2 base:部署路径关键

export default defineConfig({
  // 部署在子路径下必须设置,例如 GitHub Pages 的 /repo/
  base: '/my-app/',
})
base='/my-app/' -> 产物内所有资源引用变为 /my-app/assets/xxx.js
base='./'       -> 相对路径(适合任意目录部署)

4.3 assetsInlineLimit

export default defineConfig({
  build: {
    // 小于该值的资源转 base64 内联,减少请求数
    assetsInlineLimit: 4096, // 4KB
  },
})

5. import.meta.env 环境变量机制

5.1 注入模型

.env 文件 -> 被 Vite 加载(dotenv)-> 暴露到 import.meta.env
                │
                ├─> 前缀 VITE_ 的变量 -> 暴露给客户端代码
                └─> 非 VITE_ 前缀       -> 仅在 vite.config 中可见(loadEnv)

5.2 内置变量

变量含义
import.meta.env.MODE当前模式(development/production)
import.meta.env.DEV是否开发模式
import.meta.env.PROD是否生产模式
import.meta.env.SSR是否 SSR 构建
import.meta.env.BASE_URLbase 配置值
import.meta.env.PROD生产环境布尔值

5.3 自定义变量必须在 vite-env.d.ts 声明

// src/vite-env.d.ts
interface ImportMetaEnv {
  readonly VITE_API_URL: string
  readonly VITE_APP_TITLE: string
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}

5.4 在代码中使用

// 直接使用,构建时被静态替换
const apiBase = import.meta.env.VITE_API_URL

// 需要 TS 类型则先声明
const title: string = import.meta.env.VITE_APP_TITLE

注意:import.meta.env 是静态替换而非运行时读取——只有字面量 .VITE_XXX 会被替换,动态访问 import.meta.env[key] 不会工作。


6. .env 文件与多环境管理

6.1 文件命名与优先级

.env                 # 所有环境加载
.env.local           # 所有环境 + 本地覆盖(不入库)
.env.development     # 开发模式
.env.production      # 生产模式
.env.staging         # 需 --mode staging 显式指定
.env.local.development

优先级(从高到低):.env.local > .env.<mode> > .env。注意 .env.local 永远最高,用于本地个性化配置。

6.2 多环境典型结构

.env                       # 公共:VITE_APP_NAME=MyApp
.env.development           # VITE_API_URL=http://localhost:8080/api
.env.production            # VITE_API_URL=https://api.example.com
.env.staging               # VITE_API_URL=https://staging-api.example.com
.env.local                 # 本地调试覆盖(gitignored)

6.3 指定模式启动/构建

# 开发(默认 development)
npm run dev

# 以 staging 模式构建
vite build --mode staging

# 构建时注入的环境变量在代码中被替换
# dist 内 VITE_API_URL=https://staging-api.example.com

6.4 在 vite.config 中读取 env

import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '')
  // 此处可读取任意前缀变量(默认前缀 VITE_)
  return {
    define: {
      // 把非 VITE_ 前缀的变量注入到客户端
      __APP_VERSION__: JSON.stringify(env.VERSION),
    },
  }
})

7. 配置中的 Node 环境感知

7.1 用 Node 变量做条件

import { defineConfig } from 'vite'

export default defineConfig(({ command, mode }) => {
  const isProd = mode === 'production'

  return {
    define: {
      // 生产才启用某些全局
      __DEV__: JSON.stringify(!isProd),
    },
    plugins: [
      // 根据环境启用不同插件
      isProd ? productionPlugin() : devPlugin(),
    ],
    build: {
      sourcemap: !isProd, // 生产关闭 sourcemap
    },
  }
})

7.2 环境变量在配置内 vs 配置外

位置能访问典型用途
vite.config.ts全部(含无前缀)插件配置、define、代理
客户端代码仅 VITE_ 前缀业务常量、API 地址

边界:任何需要保密的密钥(如数据库密码、签名私钥)都不应加 VITE_ 前缀——它会被打包进产物、公开可见。


8. 常见陷阱与调试

8.1 陷阱清单

现象原因解决
环境变量是 undefined变量无 VITE_ 前缀添加前缀
TS 报 env 不存在未声明 ImportMetaEnv补充 vite-env.d.ts
代理不生效rewrite 写错 / target 不可达检查 target + changeOrigin
子路径部署资源 404未设置 base配置 base 或 ./
动态 env 访问失效import.meta.env[key] 无法替换用字面量访问

8.2 调试技巧

// 临时打印完整 env
console.log(loadEnv(mode, process.cwd(), ''))

// 查看最终解析配置
npx vite --debug

8.3 用 –debug 追踪代理

vite --debug | grep proxy

9. 总结:配置的分层心智模型

9.1 一句话框架

resolve(怎么找文件) -> server(怎么开发) -> build(怎么发布) -> env(怎么区分环境)

9.2 核心规则

  1. 命令行 > 配置文件 > 默认值,浅层合并。
  2. VITE_ 前缀决定客户端可见性,密钥绝不加前缀。
  3. import.meta.env 是静态替换,务必用字面量。
  4. base 决定部署路径,子路径部署必配。
  5. 代理解决开发期跨域,rewrite 控制路径映射。

9.3 自检清单

检查项是否掌握
能说出配置加载优先级☐
能配置 proxy + rewrite☐
能实现多环境 .env 管理☐
能理解 base 对产物路径的影响☐
能解释 VITE_ 前缀边界☐

延伸阅读

  • https://plumephp.com/vite-scaffold-engineering/ — 脚手架与工程化起步
  • https://plumephp.com/vite-build-optimization/ — 生产构建优化
  • https://plumephp.com/vite-plugin-development/ — 用插件扩展配置能力
  • Vite 配置参考文档 — 全部配置项官方索引
  • Vite 环境变量与模式

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「vite」更多文章

  1. Vite 静态资源与媒体资产处理:图片、字体、SVG 与 Worker
  2. Vite 环境变量与生产构建最佳实践:import.meta.env、构建模式与产物优化
  3. Vite 浏览器兼容与 Legacy 构建:build.target、Polyfill 与兼容插件