Vue 3 项目环境配置全解析:Webpack vs Vite

1. 基础概念对比

Webpack 环境变量

  • 访问方式process.env.XXX
  • 定义文件.env.env.production.env.development
  • 变量注入:通过 DefinePlugin 在构建时注入
  • 默认变量NODE_ENV (development/production/test)

Vite 环境变量

  • 访问方式import.meta.env.XXX
  • 定义文件.env.env.production.env.development
  • 变量注入:开发时直接可用,生产时构建注入
  • 默认变量
    • MODE:当前模式
    • PROD:是否生产环境(布尔值)
    • DEV:是否开发环境(布尔值)
    • SSR:是否服务端渲染

2. 环境文件配置

文件命名规则(两者通用)

1
2
3
4
.env                # 所有环境都会加载
.env.local # 所有环境都会加载,但会被 git 忽略
.env.[mode] # 特定模式加载(如 .env.production)
.env.[mode].local # 特定模式加载,但会被 git 忽略

加载优先级(从高到低)

  1. .env.[mode].local
  2. .env.[mode]
  3. .env.local
  4. .env

3. Webpack 环境配置(Vue CLI)

基本配置

1
2
3
# .env.development
NODE_ENV=development
VUE_APP_API_URL=http://dev-api.example.com
1
2
3
# .env.test
NODE_ENV=production
VUE_APP_API_URL=http://test-api.example.com
1
2
3
# .env.production
NODE_ENV=production
VUE_APP_API_URL=http://api.example.com

变量命名规则

  • 必须以 VUE_APP_ 开头才会被 Vue CLI 暴露给客户端代码
  • NODE_ENVBASE_URL 是内置变量

在代码中使用

1
2
3
// Webpack 项目
console.log(process.env.NODE_ENV); // 'development'/'production'
console.log(process.env.VUE_APP_API_URL); // API URL

构建命令

1
2
3
4
5
6
7
8
# 开发环境
npm run serve

# 测试环境
npm run build --mode test

# 生产环境
npm run build

4. Vite 环境配置

基本配置

1
2
# .env.development
VITE_APP_API_URL=http://dev-api.example.com
1
2
3
# .env.test
# NODE_ENV 可以省略,Vite 自动处理
VITE_APP_API_URL=http://test-api.example.com
1
2
3
# .env.production
# NODE_ENV 可以省略,Vite 自动处理
VITE_APP_API_URL=http://api.example.com

变量命名规则

  • 必须以 VITE_ 开头才会暴露给客户端代码
  • Vite 提供内置变量: MODE, DEV, PROD

在代码中使用

1
2
3
4
5
6
7
8
9
10
11
// Vite 项目
console.log(import.meta.env.MODE); // 'development'/'production'/'test'
console.log(import.meta.env.PROD); // true/false
console.log(import.meta.env.DEV); // true/false
console.log(import.meta.env.VITE_APP_API_URL); // API URL

// ❌ 不要这样使用,这是错误的
// console.log(import.meta.env.NODE_ENV); // 不存在!

// 如需兼容旧代码,Vite 保留了对 process.env.NODE_ENV 的支持
console.log(process.env.NODE_ENV); // 'development'/'production'

构建命令

1
2
3
4
5
6
7
8
# 开发环境
npm run dev

# 测试环境
npm run build --mode test

# 生产环境
npm run build

5. 完整项目配置示例

Vue 3 + Vite 项目

目录结构

1
2
3
4
5
6
7
8
9
project/
├── .env # 基础环境变量
├── .env.development # 开发环境变量
├── .env.test # 测试环境变量
├── .env.production # 生产环境变量
├── vite.config.ts # Vite 配置
└── src/
└── utils/
└── request.ts # API 请求配置

环境文件内容

1
2
# .env (基础配置)
VITE_APP_TITLE=我的应用
1
2
3
4
5
# .env.development
VITE_APP_ENV=development
VITE_APP_API_URL=http://localhost:3000
VITE_APP_UPLOAD_URL=http://localhost:3000/upload
VITE_APP_BASE_URL=/
1
2
3
4
5
# .env.test
VITE_APP_ENV=test
VITE_APP_API_URL=https://test-api.example.com
VITE_APP_UPLOAD_URL=https://test-api.example.com/upload
VITE_APP_BASE_URL=/app/
1
2
3
4
5
# .env.production
VITE_APP_ENV=production
VITE_APP_API_URL=https://api.example.com
VITE_APP_UPLOAD_URL=https://api.example.com/upload
VITE_APP_BASE_URL=/app/

vite.config.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';

export default defineConfig(({ command, mode }) => {
// 加载环境变量
const env = loadEnv(mode, process.cwd());

return {
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
},
base: env.VITE_APP_BASE_URL,
server: {
port: 3000,
open: true,
proxy: {
'/api': {
target: env.VITE_APP_API_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
build: {
outDir: 'dist',
assetsDir: 'assets',
sourcemap: mode !== 'production'
}
};
});

请求配置 (src/utils/request.ts)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import axios from 'axios';

// ✅ 正确的方式
const baseURL = import.meta.env.VITE_APP_API_URL;
// 可以直接使用布尔值判断环境
const isProd = import.meta.env.PROD;
const isDev = import.meta.env.DEV;
const currentMode = import.meta.env.MODE;

const service = axios.create({
baseURL,
timeout: 5000,
headers: {
'Content-Type': 'application/json'
}
});

// 根据环境配置请求拦截器
service.interceptors.request.use(config => {
// 开发环境打印请求信息
if (isDev) {
console.log('请求地址:', `${config.baseURL}${config.url}`);
}

// 不同环境可能有不同的认证方式
if (currentMode === 'test') {
// 测试环境特殊处理
config.headers.Authorization = `Bearer ${import.meta.env.VITE_APP_TEST_TOKEN}`;
} else {
// 生产/开发环境
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
}

return config;
});

export default service;

6. 从 Webpack 迁移到 Vite 的注意事项

  1. 环境变量前缀变更

    • Webpack: VUE_APP_* → Vite: VITE_*
  2. 访问方式变更

    • Webpack: process.env.* → Vite: import.meta.env.*
  3. 环境判断方式

    • Webpack: process.env.NODE_ENV === 'production'
    • Vite: import.meta.env.PROD (布尔值)
  4. 环境变量类型

    • Webpack 中所有环境变量都是字符串
    • Vite 中 PRODDEV 是布尔值
  5. 更改代码示例

    1
    2
    3
    4
    5
    6
    7
    // 修改前 (Webpack)
    const isProd = process.env.NODE_ENV === 'production';
    const apiUrl = process.env.VUE_APP_API_URL;

    // 修改后 (Vite)
    const isProd = import.meta.env.PROD;
    const apiUrl = import.meta.env.VITE_APP_API_URL;

7. 最佳实践

  1. 创建环境工具函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // src/utils/env.ts
    export const getEnv = (): string => import.meta.env.MODE;
    export const isProd = (): boolean => import.meta.env.PROD;
    export const isDev = (): boolean => import.meta.env.DEV;
    export const isTest = (): boolean => getEnv() === 'test';

    // 获取环境变量,提供默认值和类型转换
    export const getEnvValue = <T extends string | boolean | number>(
    key: string,
    defaultValue: T
    ): T => {
    const value = import.meta.env[key] as unknown;
    if (value === undefined) return defaultValue;

    // 根据默认值类型进行转换
    if (typeof defaultValue === 'boolean') {
    return (value === 'true') as unknown as T;
    }
    if (typeof defaultValue === 'number') {
    return Number(value) as unknown as T;
    }
    return value as T;
    };

    // 使用示例
    export const getApiUrl = () => getEnvValue('VITE_APP_API_URL', '');
    export const getAppTitle = () => getEnvValue('VITE_APP_TITLE', '默认应用名称');
  2. 在组件中使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <script setup lang="ts">
    import { getAppTitle, isProd, isTest } from '@/utils/env';

    // 根据环境显示不同内容
    const showDebugInfo = !isProd();
    const showTestBanner = isTest();
    const appTitle = getAppTitle();
    </script>

    <template>
    <div>
    <h1>{{ appTitle }}</h1>
    <div v-if="showTestBanner" class="test-env-banner">测试环境</div>
    <div v-if="showDebugInfo" class="debug-info">Debug模式已启用</div>
    </div>
    </template>

通过这种环境配置和使用方式,可以在 Vue 3 项目中灵活处理不同环境的配置需求,同时保持代码的可维护性和清晰度。