Files
2026-10-11 19:39:51 +08:00

408 lines
11 KiB
Markdown
Raw Permalink 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 / pnpm build:prod)
└── .env.test # 测试构建(pnpm build:test)
```
**加载优先级:** `.env.{mode}` > `.env`(Vite 标准加载规则,可用 `.env.{mode}.local` 做本地覆盖)
## 开发环境配置
### `.env.development`
```bash
# 只在开发模式中被载入
VITE_PORT = 8001
# 网站根目录
VITE_PUBLIC_PATH = /
# 是否开启mock
VITE_USE_MOCK = false
# 网站前缀
VITE_BASE_URL = /
# 是否删除console
VITE_DROP_CONSOLE = true
# 跨域代理,可以配置多个,请注意不要换行
VITE_PROXY=[["/api","http://admin.laravel13.naivevue/api"]]
# API 接口地址
VITE_GLOB_API_URL =
# 图片上传地址
VITE_GLOB_UPLOAD_URL =
# 图片前缀地址
VITE_GLOB_IMG_URL =
# 接口前缀
VITE_GLOB_API_URL_PREFIX = /api
```
:::tip 代理目标地址
`VITE_PROXY` 是开发代理的唯一配置来源,当前值指向 Laragon 虚拟主机 `http://admin.laravel13.naivevue/api`(见 [2.2 Laragon 环境搭建](/zh/quickstart/laragon.html))。修改后需重启 `pnpm dev` 生效。
:::
## 生产环境配置
### `.env.production`
```bash
# 是否开启mock
VITE_USE_MOCK = false
# 网站根目录
VITE_PUBLIC_PATH = /
# 网站前缀
VITE_BASE_URL = /
# 是否删除console
VITE_DROP_CONSOLE = true
# API
VITE_GLOB_API_URL =
# 图片上传地址
VITE_GLOB_UPLOAD_URL =
# 图片前缀地址
VITE_GLOB_IMG_URL =
# 接口前缀
VITE_GLOB_API_URL_PREFIX = /api
# 是否启用gzip压缩或brotli压缩
# 可选: gzip | brotli | none
# 如果你需要多种形式,你可以用','来分隔
VITE_BUILD_COMPRESS = 'none'
# 使用压缩时是否删除原始文件,默认为false
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
```
:::info 生产环境没有 VITE_PROXY
`VITE_PROXY` 仅在开发模式由 Vite dev server 使用;生产环境由 Nginx 反向代理 `/api`(见下方部署配置)。
:::
## 环境变量详解
### 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.naivevue/api"]]
```
**格式:** JSON 数组,每项为 `[前缀, 目标地址]`
**作用:** 将前端 `/api/*` 请求代理到后端地址,解决开发环境跨域问题(代理方式下不依赖后端 CORS 配置)。
**多代理示例:**
```bash
VITE_PROXY = [["/api","http://admin.laravel13.naivevue/api"],["/uploads","http://admin.laravel13.naivevue/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 ({ command, mode }: ConfigEnv): UserConfig => {
const root = process.cwd();
const env = loadEnv(mode, root);
const viteEnv = wrapperEnv(env); // VITE_PROXY 在此由字符串 JSON.parse 为数组(见 build/utils.ts)
const { VITE_PUBLIC_PATH, VITE_PORT, VITE_GLOB_PROD_MOCK, VITE_PROXY } = viteEnv;
return {
base: VITE_PUBLIC_PATH,
server: {
host: true,
port: VITE_PORT, // 端口来自 .env.development 的 VITE_PORT
proxy: createProxy(VITE_PROXY), // 见 build/vite/proxy.ts
},
// ... 插件、路径别名等见 ui/vite.config.ts 全文
};
};
// ui/build/utils.ts —— wrapperEnv 中对 VITE_PROXY 做 JSON 解析
if (envName === 'VITE_PROXY') {
try {
realName = JSON.parse(realName);
} catch (error) {}
}
// 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://admin.laravel13.naivevue/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://admin.laravel13.naivevue/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 相关(分包)
├── 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;
}
```
## 多环境配置
### 测试环境(项目实际提供)
```bash
# .env.test(pnpm build:test)
VITE_USE_MOCK = true
VITE_PUBLIC_PATH = /
VITE_BASE_URL = /
VITE_DROP_CONSOLE = true
VITE_GLOB_API_URL =
VITE_GLOB_UPLOAD_URL =
VITE_GLOB_IMG_URL =
VITE_GLOB_API_URL_PREFIX = /api
VITE_BUILD_COMPRESS = 'none'
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
```
构建命令(见 `ui/package.json` scripts):
```bash
pnpm build:test # 测试环境构建
pnpm build:prod # 生产环境构建(与 pnpm build 等价)
```
### 环境变量对照表
| 变量 | 开发 | 测试 | 生产 |
|------|------|------|------|
| `VITE_PORT` | 8001 | - | - |
| `VITE_BASE_URL` | / | / | / |
| `VITE_GLOB_API_URL` | 留空 | 留空 | 留空 |
| `VITE_GLOB_API_URL_PREFIX` | /api | /api | /api |
| `VITE_PROXY` | `[["/api","http://admin.laravel13.naivevue/api"]]` | - | - |
| `VITE_GLOB_IMG_URL` | 留空 | 留空 | 留空(按需配置 CDN) |
| `VITE_DROP_CONSOLE` | true | true | true |
| `VITE_USE_MOCK` | false | true | false |
## 常见问题
### 问题 1:开发环境 API 请求 404
**原因:** 代理配置错误或后端未启动。
**解决:** 检查 `.env.development` 中 `VITE_PROXY` 的目标地址是否正确,`curl http://admin.laravel13.naivevue/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` 分包。