--- kind: configuration_system name: 前后端配置系统与环境变量管理 category: configuration_system scope: - '**' source_files: - backend/src/app.js - backend/src/config/loadEnv.js - backend/src/config/env.js - backend/src/config/database.js - backend/src/config/redis.js - backend/src/config/logger.js - docker-compose.yml - frontend/.env - frontend/.env.prod - frontend/.env.test - frontend/vite.config.ts --- ## 1. 系统概览 本项目采用**前后端分离 + Docker Compose 编排**的架构,配置系统围绕“环境变量优先、文件兜底”的原则组织: - **后端(Node.js/Express)**:通过 `dotenv` 从仓库根目录 `.env` 加载,Docker 部署时由 `docker-compose.yml` 的 `env_file` 注入,不覆盖已有环境变量。 - **前端(Vite)**:使用 Vite 内置的 `loadEnv`,按构建模式(development / test / production)分别读取 `.env`、`.env.test`、`.env.prod`,所有 `VITE_` 前缀变量在构建期注入到 `import.meta.env`。 - **容器编排**:`docker-compose.yml` 通过 `env_file` 和 `environment` 为后端注入运行时配置,并通过端口映射与 Nginx 静态资源卷完成服务暴露。 ## 2. 关键文件与包 | 层级 | 文件 | 作用 | |------|------|------| | 后端入口 | `backend/src/app.js` | 首行 `require('./config/loadEnv')` 触发 .env 加载;集中挂载中间件、路由、启动监听 | | 环境判断 | `backend/src/config/env.js` | 基于 `APP_ENV` 导出 `isDevelopment` / `isProduction` 布尔值 | | 环境变量加载 | `backend/src/config/loadEnv.js` | 仅当根目录存在 `.env` 时才调用 `dotenv.config`,避免覆盖容器注入的环境变量 | | 数据库配置 | `backend/src/config/database.js` | 从 `DATABASE_*` 环境变量构造 Sequelize 实例,开发模式开启 SQL 日志 | | Redis 缓存 | `backend/src/config/redis.js` | 懒初始化 ioredis 客户端,支持密码与多 DB 选择 | | 日志配置 | `backend/src/config/logger.js` | winston 双传输(Console + File),固定输出到 `backend/logs/app.log` | | 容器编排 | `docker-compose.yml` | 定义 backend/frontend 两个服务,通过 `env_file: .env` 注入后端配置,固定 `PORT=8000` | | 前端基础配置 | `frontend/.env` | 应用标题、路由模式、代理开关等通用 Vite 变量 | | 前端生产配置 | `frontend/.env.prod` | 指定 `VITE_SERVICE_BASE_URL=/api`(同域 Nginx 反代) | | 前端测试配置 | `frontend/.env.test` | 指向本地后端 `http://localhost:8083/api` | | Vite 构建脚本 | `frontend/vite.config.ts` | 通过 `loadEnv(mode, cwd)` 读取对应 `.env.*`,并注入 `base`、`proxy`、`define` 等 | ## 3. 架构与设计约定 ### 3.1 后端配置加载顺序 ``` 进程启动 → app.js → require('./config/loadEnv') → dotenv.config({ path: root/.env }) // 仅当文件存在 → 各模块直接 process.env.XXX 取值 ``` - **优先级**:容器注入环境变量 > `.env` 文件默认值(`process.env.DATABASE_PASSWORD || 'root123'`)。 - **环境区分**:`APP_ENV` 决定 `isDevelopment` / `isProduction`,用于控制 Sequelize SQL 日志开关等。 ### 3.2 前端配置加载顺序 ``` vite serve/build → loadEnv(mode, cwd) → development: 读取 .env + .env.development → test: 读取 .env + .env.test → production: 读取 .env + .env.prod → 仅 VITE_* 前缀变量注入到 import.meta.env ``` - 生产构建产物不包含源码,因此 `VITE_SERVICE_BASE_URL=/api` 通过 Nginx 反向代理到后端 `/api`,实现同源部署。 - 开发/测试环境通过 `VITE_HTTP_PROXY=Y` 配合 `createViteProxy` 将请求转发到 `http://localhost:8083`。 ### 3.3 容器化配置 - 后端容器内固定 `PORT=8000`,宿主机映射 `8083:8000`,与 Nginx `proxy_pass http://backend:8000` 一致。 - `extra_hosts: host.docker.internal:host-gateway` 允许容器访问宿主机 MySQL/Redis。 - 前端容器只挂载静态资源与 nginx.conf,无运行时配置。 ## 4. 开发者应遵循的规则 1. **新增后端环境变量**:统一以 `DATABASE_*`、`REDIS_*`、`PORT`、`APP_ENV` 等大写命名,在 `backend/src/config/*.js` 中提供默认值,并在 `docker-compose.yml` 的 `env_file` 或 `environment` 中声明。 2. **不要修改 `loadEnv.js` 的加载逻辑**:它刻意只在本地存在 `.env` 时才加载,避免覆盖 Docker 注入的环境变量。 3. **新增前端环境变量**:必须以 `VITE_` 开头,放在对应环境的 `.env.*` 文件中;若需跨环境共享,放入根 `.env`。 4. **生产部署**:确保 `frontend/.env.prod` 的 `VITE_SERVICE_BASE_URL` 与 Nginx 的反代路径一致(当前为 `/api`)。 5. **敏感信息**:数据库密码、Redis 密码等不要提交到版本库,使用 `docker-compose.yml` 的 `env_file` 或宿主机的环境变量注入。 6. **日志位置**:后端日志固定写入 `backend/logs/app.log`,容器内可通过 volume 持久化到宿主机 `/data/projects/source`。