# 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` 分包。