# 情绪博物馆前端环境配置梳理 ## 1. 项目概述 情绪博物馆前端基于Vue3 + TypeScript + Vite开发,采用现代化的前端技术栈,支持多环境部署。 ### 技术栈 - **框架**: Vue 3.4.0 - **构建工具**: Vite 5.0.8 - **语言**: TypeScript 5.3.3 - **UI框架**: Element Plus 2.4.4 - **状态管理**: Pinia 2.1.7 - **路由**: Vue Router 4.2.5 - **样式**: Tailwind CSS 3.4.0 - **HTTP客户端**: Axios 1.6.2 - **WebSocket**: Socket.io-client 4.7.4, @stomp/stompjs 7.1.1 - **图表**: ECharts 5.4.3 - **工具库**: Day.js, Lodash-es, Zod ## 2. 环境配置文件 ### 2.1 环境变量类型定义 (`src/types/env.d.ts`) ```typescript interface ImportMetaEnv { readonly VITE_APP_ENV: string // 应用环境 readonly VITE_APP_TITLE: string // 应用标题 readonly VITE_APP_VERSION: string // 应用版本 readonly VITE_API_BASE_URL: string // API基础URL readonly VITE_WS_BASE_URL: string // WebSocket基础URL readonly VITE_UPLOAD_URL: string // 文件上传URL readonly VITE_DEBUG: string // 调试模式 readonly VITE_MOCK: string // Mock模式 readonly VITE_APP_DESCRIPTION: string // 应用描述 } ``` ### 2.2 环境配置管理 (`src/config/env.ts`) 环境配置支持四种环境: - **local**: 本地开发环境 - **dev**: 开发环境 - **test**: 测试环境 - **prod**: 生产环境 #### 环境配置接口 ```typescript interface EnvConfig { name: string // 环境名称 apiBaseUrl: string // API基础URL wsBaseUrl: string // WebSocket URL uploadUrl: string // 文件上传URL debug: boolean // 调试模式 mock: boolean // Mock模式 appTitle: string // 应用标题 appVersion: string // 应用版本 } ``` #### 各环境配置详情 **本地环境 (local)** ```typescript { name: '本地环境', apiBaseUrl: 'http://localhost:19089/api', wsBaseUrl: 'ws://localhost:19089/api', uploadUrl: 'http://localhost:19089/api/upload', debug: true, mock: false, appTitle: '情绪博物馆 - 本地', appVersion: '1.0.0' } ``` **开发环境 (dev)** ```typescript { name: '开发环境', apiBaseUrl: 'http://localhost:19089/api', wsBaseUrl: 'ws://localhost:19089/api', uploadUrl: 'http://localhost:19089/api/upload', debug: true, mock: false, appTitle: '情绪博物馆 - 开发', appVersion: '1.0.0' } ``` **测试环境 (test)** ```typescript { name: '测试环境', apiBaseUrl: 'http://test.emotion-museum.com/api', wsBaseUrl: 'ws://test.emotion-museum.com', uploadUrl: 'http://test.emotion-museum.com/api/upload', debug: false, mock: false, appTitle: '情绪博物馆 - 测试', appVersion: '1.0.0' } ``` **生产环境 (prod)** ```typescript { name: '生产环境', apiBaseUrl: 'https://api.emotion-museum.com/api', wsBaseUrl: 'wss://api.emotion-museum.com', uploadUrl: 'https://api.emotion-museum.com/api/upload', debug: false, mock: false, appTitle: '情绪博物馆', appVersion: '1.0.0' } ``` ## 3. 构建配置 ### 3.1 Vite配置 (`vite.config.ts`) ```typescript export default defineConfig({ base: '/emotion-museum/', // 部署基础路径 plugins: [vue()], resolve: { alias: { '@': resolve(__dirname, 'src'), // 路径别名 }, }, define: { global: 'globalThis', // 全局变量定义 }, server: { port: 5173, // 开发服务器端口 open: true, // 自动打开浏览器 proxy: { // 代理配置 '/api': { target: 'http://localhost:19089', changeOrigin: true, secure: false, } } }, build: { outDir: 'dist', // 输出目录 sourcemap: false, // 不生成sourcemap rollupOptions: { external: (id) => { // 外部依赖处理 if (id.includes('echarts') && id.includes('extension')) { return true } return false }, output: { manualChunks: { // 代码分割 vendor: ['vue', 'vue-router', 'pinia'], elementPlus: ['element-plus'], }, }, }, }, }) ``` ### 3.2 TypeScript配置 (`tsconfig.json`) ```json { "compilerOptions": { "target": "ES2020", // 目标版本 "useDefineForClassFields": true, "lib": ["ES2020", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true, "moduleResolution": "bundler", // 模块解析策略 "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "preserve", "strict": true, // 严格模式 "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "baseUrl": ".", "paths": { // 路径映射 "@/*": ["src/*"] }, "allowSyntheticDefaultImports": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "types": ["node"] }, "include": [ "src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/types/global.d.ts" ], "references": [{ "path": "./tsconfig.node.json" }] } ``` ### 3.3 Tailwind CSS配置 (`tailwind.config.js`) ```javascript export default { content: [ "./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}", ], theme: { extend: { colors: { primary: { // 主色调 50: '#f0f9ff', 100: '#e0f2fe', 200: '#bae6fd', 300: '#7dd3fc', 400: '#38bdf8', 500: '#0ea5e9', 600: '#0284c7', 700: '#0369a1', 800: '#075985', 900: '#0c4a6e', }, emotion: { // 情绪色彩 happy: '#fbbf24', sad: '#3b82f6', angry: '#ef4444', calm: '#10b981', excited: '#f97316', anxious: '#8b5cf6', }, // 设计系统颜色 'tech-blue': '#4A90E2', 'warm-orange': '#F5A623', 'light-gray': '#F7F8FA', 'text-dark': '#333333', 'text-medium': '#888888', }, fontFamily: { sans: ['Noto Sans SC', 'Inter', 'system-ui', 'sans-serif'], }, animation: { // 自定义动画 'fade-in': 'fadeIn 0.5s ease-in-out', 'slide-up': 'slideUp 0.3s ease-out', 'bounce-gentle': 'bounceGentle 2s infinite', }, keyframes: { fadeIn: { '0%': { opacity: '0' }, '100%': { opacity: '1' }, }, slideUp: { '0%': { transform: 'translateY(20px)', opacity: '0' }, '100%': { transform: 'translateY(0)', opacity: '1' }, }, bounceGentle: { '0%, 100%': { transform: 'translateY(0)' }, '50%': { transform: 'translateY(-5px)' }, }, }, }, }, plugins: [], } ``` ### 3.4 PostCSS配置 (`postcss.config.js`) ```javascript export default { plugins: { tailwindcss: {}, // Tailwind CSS autoprefixer: {}, // 自动添加CSS前缀 }, } ``` ## 4. 代码规范配置 ### 4.1 ESLint配置 (`.eslintrc.cjs`) ```javascript module.exports = { root: true, extends: [ 'plugin:vue/vue3-essential', // Vue3基础规则 'eslint:recommended', // ESLint推荐规则 '@vue/eslint-config-typescript', // TypeScript规则 '@vue/eslint-config-prettier/skip-formatting' // Prettier集成 ], parserOptions: { ecmaVersion: 'latest' }, rules: { 'vue/multi-word-component-names': 'off', // 允许单词组件名 '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], // 忽略下划线参数 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 生产环境警告console 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' // 生产环境警告debugger } } ``` ### 4.2 Prettier配置 (`.prettierrc`) ```json { "semi": false, // 不使用分号 "singleQuote": true, // 使用单引号 "tabWidth": 2, // 缩进2个空格 "trailingComma": "es5", // ES5兼容的尾随逗号 "printWidth": 100, // 行宽100字符 "bracketSpacing": true, // 对象字面量括号内空格 "arrowParens": "avoid" // 箭头函数参数避免括号 } ``` ## 5. HTTP请求配置 ### 5.1 请求工具配置 (`src/utils/request.ts`) #### 基础配置 ```typescript const instance = axios.create({ baseURL: envConfig.apiBaseUrl, // 从环境配置获取基础URL timeout: 30000, // 30秒超时 headers: { 'Content-Type': 'application/json;charset=UTF-8' } }) ``` #### 请求拦截器 - 自动添加Authorization头(Bearer Token) - 生成请求ID用于追踪 - 调试模式下打印请求日志 #### 响应拦截器 - 统一处理业务状态码 - 特殊错误码处理(401、403、404、500等) - 自动处理未授权情况 - 调试模式下打印响应日志 #### 错误处理 - 网络错误处理 - 服务器错误处理 - 业务错误处理 - 401未授权自动跳转登录 ## 6. 部署配置 ### 6.1 构建脚本 (`package.json`) ```json { "scripts": { "dev": "vite", // 开发环境 "build": "vite build", // 生产构建 "build:check": "vue-tsc && vite build", // 类型检查+构建 "preview": "vite preview", // 预览构建结果 "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", "type-check": "vue-tsc --noEmit", // TypeScript类型检查 "test": "vitest", // 单元测试 "test:e2e": "cypress run" // E2E测试 } } ``` ### 6.2 Linux部署脚本 (`deploy.sh`) ```bash #!/bin/bash # 部署脚本 - 将构建好的文件上传到服务器 SERVER_IP="47.111.10.27" USERNAME="root" REMOTE_PATH="/data/www/emotion-museum" # 检查dist目录是否存在 if [ ! -d "dist" ]; then echo "错误: dist目录不存在,请先运行 npm run build" exit 1 fi # 上传文件到服务器 scp dist/index.html "${USERNAME}@${SERVER_IP}:${REMOTE_PATH}/" scp -r dist/assets "${USERNAME}@${SERVER_IP}:${REMOTE_PATH}/" scp dist/test-*.html "${USERNAME}@${SERVER_IP}:${REMOTE_PATH}/" ``` ### 6.3 Windows部署脚本 (`deploy.ps1`) ```powershell # 部署脚本 - PowerShell版本 param( [string]$ServerIP = "47.111.10.27", [string]$Username = "root", [string]$RemotePath = "/data/www/emotion-museum" ) # 检查dist目录 if (-not (Test-Path "dist")) { Write-Host "错误: dist目录不存在,请先运行 npm run build" -ForegroundColor Red exit 1 } # 上传文件到服务器 scp "dist/index.html" "${Username}@${ServerIP}:${RemotePath}/" scp -r "dist/assets" "${Username}@${ServerIP}:${RemotePath}/" scp "dist/test-*.html" "${Username}@${ServerIP}:${RemotePath}/" ``` ## 7. 环境变量使用 ### 7.1 环境变量获取方式 ```typescript // 在组件中使用环境变量 const apiUrl = import.meta.env.VITE_API_BASE_URL const isDebug = import.meta.env.VITE_DEBUG === 'true' const appTitle = import.meta.env.VITE_APP_TITLE ``` ### 7.2 环境变量设置 开发时可以通过以下方式设置环境变量: **Linux/Mac:** ```bash export VITE_APP_ENV=dev export VITE_API_BASE_URL=http://localhost:19089/api npm run dev ``` **Windows:** ```cmd set VITE_APP_ENV=dev set VITE_API_BASE_URL=http://localhost:19089/api npm run dev ``` **或者创建.env文件:** ```env VITE_APP_ENV=dev VITE_API_BASE_URL=http://localhost:19089/api VITE_WS_BASE_URL=ws://localhost:19089/api VITE_DEBUG=true VITE_MOCK=false ``` ## 8. 开发环境配置 ### 8.1 开发服务器配置 - **端口**: 5173 - **自动打开**: 是 - **代理**: `/api` -> `http://localhost:19089` - **热更新**: 启用 ### 8.2 调试配置 - **Vue DevTools**: 支持 - **TypeScript**: 严格模式 - **ESLint**: 实时检查 - **Prettier**: 自动格式化 ### 8.3 构建优化 - **代码分割**: 按模块分割 - **Tree Shaking**: 自动移除未使用代码 - **压缩**: 生产环境自动压缩 - **缓存**: 文件名包含哈希值 ## 9. 生产环境配置 ### 9.1 构建优化 - **Source Map**: 禁用 - **压缩**: 启用 - **代码分割**: 启用 - **CDN**: 支持 ### 9.2 部署路径 - **基础路径**: `/emotion-museum/` - **静态资源**: 自动添加哈希值 - **缓存策略**: 长期缓存静态资源 ### 9.3 性能优化 - **懒加载**: 路由级别懒加载 - **预加载**: 关键资源预加载 - **压缩**: Gzip/Brotli压缩 - **缓存**: 浏览器缓存优化 ## 10. 注意事项 1. **环境变量**: 必须以`VITE_`开头才能在客户端使用 2. **API代理**: 开发环境使用代理,生产环境使用真实域名 3. **WebSocket**: 开发环境使用ws协议,生产环境使用wss协议 4. **构建路径**: 确保部署路径与`vite.config.ts`中的`base`配置一致 5. **类型检查**: 构建前建议运行`npm run type-check`确保类型安全 6. **代码规范**: 提交前运行`npm run lint`确保代码质量 ## 11. 故障排除 ### 常见问题 1. **构建失败**: 检查TypeScript类型错误 2. **代理不生效**: 检查vite.config.ts中的proxy配置 3. **环境变量未生效**: 确保变量名以`VITE_`开头 4. **部署404**: 检查nginx配置和base路径设置 5. **WebSocket连接失败**: 检查协议和端口配置 ### 调试技巧 1. 使用浏览器开发者工具查看网络请求 2. 检查控制台错误信息 3. 使用Vue DevTools调试组件状态 4. 查看构建日志定位问题