Files
rxthinkcmf-wiki/RXThinkCMF_Laravel13_EleVue/zh/frontend/env-config.md
T
2026-10-08 17:50:29 +08:00

398 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 9.3 环境与构建配置
:::tip 概述
本节说明前端项目的环境变量配置和 Vite 构建配置,包括开发环境和生产环境的差异配置。前端通过 `.env` 文件管理环境变量,Vite 自动根据模式加载对应的 `.env` 文件。
:::
## 环境变量文件
```text
ui/
├── .env # 所有环境通用配置(端口、标题)
├── .env.development # 开发环境(pnpm dev,默认 mode)
├── .env.production # 生产构建(pnpm build)
├── .env.test # 测试构建(pnpm build:test)
├── .env.uat # UAT 构建(pnpm build:uat)
└── .env.dev # dev 模式构建(pnpm build:dev)
```
**加载优先级:** `.env.{mode}` > `.env`(Vite 标准加载规则,可用 `.env.{mode}.local` 做本地覆盖)
## 开发环境配置
### `.env.development`
```bash
# 开发服务器端口
VITE_PORT = 8001
# 公共基础路径(通常为 /)
VITE_PUBLIC_PATH = /
# 是否启用 Mock 数据(false = 使用真实后端 API)
VITE_USE_MOCK = false
# 是否删除 console(当前项目开发构建同样删除)
VITE_DROP_CONSOLE = true
# 开发代理(JSON 数组格式:[["前缀","目标地址"]])
VITE_PROXY=[["/api","http://admin.laravel13.elevue/api"]]
# API 接口基础路径(留空,由代理处理)
VITE_GLOB_API_URL =
# 上传接口地址(留空,走同域/代理)
VITE_GLOB_UPLOAD_URL=
# 图片前缀地址(留空,按后端返回的地址解析)
VITE_GLOB_IMG_URL=
# 构建压缩方式:none / gzip / brotli
VITE_BUILD_COMPRESS = 'none'
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
# API 前缀(所有接口路径的前缀)
VITE_GLOB_API_URL_PREFIX = /api
```
:::tip 代理目标地址
`VITE_PROXY` 当前默认指向 Laragon 虚拟主机 `http://admin.laravel13.elevue/api`;使用 `php artisan serve` 时改为直连 `http://localhost:8000/api`(见 [2.2 Laragon 环境搭建](/zh/quickstart/laragon.html))。修改后需重启 `pnpm dev`。
:::
## 生产环境配置
### `.env.production`
```bash
# 是否启用 Mock 数据
VITE_USE_MOCK = false
# 公共基础路径(通常为 /,如部署到子目录则设为 /subdir/)
VITE_PUBLIC_PATH = /
# 是否删除 console
VITE_DROP_CONSOLE = true
# API 接口基础路径(留空,由 Nginx 代理处理)
VITE_GLOB_API_URL =
# 上传接口地址(留空,走同域)
VITE_GLOB_UPLOAD_URL=
# 图片前缀地址(留空;跨域部署时配置 CDN/后端域名,与 FILE_DOMAIN_URL 一致)
VITE_GLOB_IMG_URL=
# API 前缀
VITE_GLOB_API_URL_PREFIX = /api
# 构建压缩方式(当前默认 none;可选 gzip / brotli)
VITE_BUILD_COMPRESS = 'none'
# 压缩后是否删除原文件
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
```
## 环境变量详解
### VITE_PORT — 开发服务器端口
| 环境 | 值 | 说明 |
|------|-----|------|
| 开发 | `8001` | 前端开发服务器端口 |
| 生产 | 不生效 | 生产环境由 Nginx 提供服务 |
### VITE_PUBLIC_PATH — 公共基础路径
| 场景 | 值 | 说明 |
|------|-----|------|
| 根目录部署 | `/` | 默认值 |
| 子目录部署 | `/admin/` | 如 `https://example.com/admin/` |
### VITE_GLOB_API_URL — API 基础路径
| 场景 | 值 | 说明 |
|------|-----|------|
| 开发(代理) | 留空 | 由 Vite proxy 转发 |
| 生产(同域) | 留空 | 由 Nginx 代理 |
| 生产(跨域) | `https://api.example.com` | 直接请求后端域名(需后端 CORS 放行) |
### VITE_PROXY — 开发代理配置
```bash
# 当前 .env.development 中的值(Laragon 虚拟主机)
VITE_PROXY=[["/api","http://admin.laravel13.elevue/api"]]
# 直连 artisan serve 时的写法
VITE_PROXY=[["/api","http://localhost:8000/api"]]
```
**格式:** JSON 数组,每项为 `[前缀, 目标地址]`
**作用:** 将前端 `/api/*` 请求代理到后端地址,解决开发环境跨域问题(代理方式下不依赖后端 CORS 配置)。
**多代理示例:**
```bash
VITE_PROXY = [["/api","http://localhost:8000/api"],["/uploads","http://localhost:8000/uploads"]]
```
### VITE_GLOB_API_URL_PREFIX — API 前缀
```bash
VITE_GLOB_API_URL_PREFIX = /api
```
所有 API 请求路径的前缀,与后端路由前缀一致(`bootstrap/app.php` 统一添加 `/api`)。
### VITE_GLOB_UPLOAD_URL — 上传接口地址
```bash
VITE_GLOB_UPLOAD_URL=
```
文件上传组件使用的接口地址(实际调用 `/api/upload/uploadFile`)。**当前项目留空**——上传走同域/开发代理,跨域部署时再配置为后端完整地址。
### VITE_GLOB_IMG_URL — 图片访问地址
```bash
VITE_GLOB_IMG_URL=
```
用于预览上传的图片,拼接图片的完整 URL。**当前项目留空**(后端 `get_file_url()` 已按 `FILE_DOMAIN_URL` 补全域名);如配置,**必须与后端 `FILE_DOMAIN_URL` 保持一致**,否则同一张图片前后端解析出不同地址。
### VITE_DROP_CONSOLE — 删除 console
```bash
# 当前项目开发与生产构建均为 true(删除 console)
VITE_DROP_CONSOLE = true
# 需要调试时可在本地改为 false
```
### VITE_BUILD_COMPRESS — Gzip 压缩
```bash
# 当前默认关闭
VITE_BUILD_COMPRESS = 'none'
# 可选:gzip / brotli(多个用逗号分隔),启用后构建产物生成 .gz 文件,
# Nginx 配置 gzip_static on 可直接使用
VITE_BUILD_COMPRESS = 'gzip'
```
## 在代码中访问环境变量
```typescript
// 读取环境变量(VITE_ 前缀的变量才会暴露给客户端)
const apiUrl = import.meta.env.VITE_GLOB_API_URL;
const apiPrefix = import.meta.env.VITE_GLOB_API_URL_PREFIX;
const uploadUrl = import.meta.env.VITE_GLOB_UPLOAD_URL;
const imgUrl = import.meta.env.VITE_GLOB_IMG_URL;
// 完整 API 地址
const fullApiUrl = apiUrl + apiPrefix; // 如 "/api" 或 "https://api.example.com/api"
```
:::warning VITE_ 前缀
只有以 `VITE_` 开头的环境变量才会暴露给客户端代码,其他变量(如 `PORT`)不会被访问到。
:::
## Vite 配置
### `vite.config.ts`
```typescript
// ui/vite.config.ts(摘自实际代码,节选)
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd());
// VITE_PROXY 容错处理:未配置时使用空代理
let VITE_PROXY: any = viteEnv.VITE_PROXY;
if (!VITE_PROXY) {
VITE_PROXY = '[[]]'; // 默认空代理
}
if (typeof VITE_PROXY === 'string') {
VITE_PROXY = JSON.parse(VITE_PROXY);
}
return {
server: {
proxy: createProxy(VITE_PROXY), // 见 build/vite/proxy.ts
},
// ... 插件、路径别名等见 ui/vite.config.ts 全文
};
});
// ui/build/vite/proxy.ts —— 由 [前缀, 目标] 数组生成代理规则
export function createProxy(list: ProxyList = []) {
const ret: ProxyTargetList = {};
for (const [prefix, target] of list) {
ret[prefix] = {
target,
changeOrigin: true,
ws: true,
rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''), // 去掉前缀再转发
};
}
return ret;
}
```
### 代理配置详解
```typescript
// createProxy 为每个 [前缀, 目标] 生成的规则(ui/build/vite/proxy.ts 实际逻辑)
server: {
proxy: {
'/api': {
target: 'http://localhost:8000/api', // 目标地址(VITE_PROXY 驱动,含 /api 前缀)
changeOrigin: true, // 修改请求头 Origin
ws: true, // 支持 WebSocket
rewrite: (path) => path.replace(new RegExp('^/api'), ''), // 去掉前缀,由目标地址补回
},
},
}
```
**代理效果:**
```text
前端请求: GET /api/user/page
│
▼ Vite proxy
│
▼ 转发到: http://localhost:8000/api/user/page
```
## 构建命令
```bash
# 开发服务器(热更新)
pnpm dev
# 构建生产版本
pnpm build
# 预览构建结果(本地启动静态服务器)
pnpm preview
# ESLint 检查 / 自动修复
pnpm lint:eslint
pnpm lint:eslint --fix
# TypeScript 类型检查
pnpm type:check
```
### 构建产物
```text
ui/dist/
├── index.html # 入口文件
├── assets/
│ ├── index-xxx.js # 主 JS(带 hash)
│ ├── index-xxx.css # 主 CSS(带 hash)
│ ├── vue-xxx.js # Vue 相关(分包)
│ └── element-xxx.js # Element Plus(分包)
├── favicon.ico
└── static/ # 静态资源
```
## 部署配置
### Nginx 配置
```nginx
server {
listen 80;
server_name admin.example.com;
# 前端静态文件
root /data/www/admin/dist;
index index.html;
# SPA 路由(所有非文件请求都返回 index.html)
location / {
try_files $uri $uri/ /index.html;
}
# API 代理到后端
location /api/ {
proxy_pass http://127.0.0.1:8000/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 静态资源缓存
location /assets/ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# Gzip 压缩
gzip on;
gzip_static on; # 优先使用 .gz 文件
gzip_types text/css application/javascript application/json;
}
```
## 多环境配置
### 测试 / UAT 环境(项目实际提供)
```bash
# .env.test(pnpm build:test)
VITE_GLOB_API_URL =
VITE_GLOB_API_URL_PREFIX = /api
VITE_DROP_CONSOLE = true
# .env.uat(pnpm build:uat)同结构,按需调整
```
构建命令(见 `ui/package.json` scripts):
```bash
pnpm build:test # 测试环境构建
pnpm build:uat # UAT 环境构建
pnpm build:prod # 生产环境构建
```
### 环境变量对照表
| 变量 | 开发 | 测试 | 生产 |
|------|------|------|------|
| `VITE_PORT` | 8001 | - | - |
| `VITE_GLOB_API_URL` | 留空 | 留空 | 留空 |
| `VITE_GLOB_API_URL_PREFIX` | /api | /api | /api |
| `VITE_PROXY` | `[["/api","http://admin.laravel13.elevue/api"]]` | - | - |
| `VITE_GLOB_IMG_URL` | 留空 | 留空 | 留空(按需配置 CDN) |
| `VITE_DROP_CONSOLE` | true | true | true |
| `VITE_USE_MOCK` | false | false | false |
## 常见问题
### 问题 1:开发环境 API 请求 404
**原因:** 代理配置错误或后端未启动。
**解决:** 检查 `.env.development` 中 `VITE_PROXY` 的目标地址是否正确,`curl http://localhost:8000/api/captcha` 验证后端;改完配置重启 `pnpm dev`。
### 问题 2:生产环境 API 请求跨域
**原因:** `VITE_GLOB_API_URL` 配置了跨域地址但后端未配置 CORS。
**解决:** 推荐留空,由 Nginx 代理处理(同域无跨域问题);确需跨域时在后端 `.env` 配置 `CORS_ALLOW_ORIGIN`(见 [5.5 跨域资源共享](/zh/core/cors.html))。
### 问题 3:图片不显示
**原因:** `VITE_GLOB_IMG_URL` 与后端 `FILE_DOMAIN_URL` 不一致。
**解决:** 两者保持一致;改后端配置需 `php artisan config:clear`。
### 问题 4:构建后体积过大
**原因:** 未启用 gzip 压缩或未分包。
**解决:** 启用 `VITE_BUILD_COMPRESS = gzip`,配置 `manualChunks` 分包。