配置指南
本指南介绍如何配置 Trae 开发环境,包括项目设置、环境变量、构建配置等。
概述
Trae 提供了灵活的配置系统,允许您根据项目需求自定义开发环境。通过合理的配置,您可以优化开发体验、提高构建性能并确保项目的可维护性。
项目配置
基础配置文件
Trae 项目的主要配置文件是 trae.config.js,位于项目根目录:
javascript
// trae.config.js
export default {
// 项目基本信息
name: 'my-awesome-project',
version: '1.0.0',
description: 'A modern web application built with Trae',
// 开发服务器配置
server: {
port: 3000,
host: 'localhost',
https: false,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
},
cors: {
origin: ['http://localhost:3000', 'https://myapp.com'],
credentials: true
}
},
// 构建配置
build: {
outDir: 'dist',
sourcemap: true,
minify: 'terser',
target: 'es2020',
rollupOptions: {
external: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM'
}
}
}
},
// 插件配置
plugins: [
'@trae/plugin-react',
'@trae/plugin-typescript',
'@trae/plugin-eslint',
{
name: '@trae/plugin-pwa',
options: {
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg}']
}
}
}
],
// 环境配置
env: {
development: {
API_URL: 'http://localhost:8080',
DEBUG: true,
LOG_LEVEL: 'debug'
},
production: {
API_URL: 'https://api.myapp.com',
DEBUG: false,
LOG_LEVEL: 'error'
}
},
// 路径别名
alias: {
'@': './src',
'@components': './src/components',
'@utils': './src/utils',
'@assets': './src/assets',
'@styles': './src/styles'
},
// CSS 配置
css: {
preprocessorOptions: {
scss: {
additionalData: '@import "@styles/variables.scss";'
},
less: {
modifyVars: {
'primary-color': '#1890ff',
'link-color': '#1890ff'
}
}
},
modules: {
localsConvention: 'camelCase',
generateScopedName: '[name]__[local]___[hash:base64:5]'
}
},
// 优化配置
optimizeDeps: {
include: ['react', 'react-dom', 'lodash'],
exclude: ['@trae/dev-tools']
},
// 测试配置
test: {
globals: true,
environment: 'jsdom',
setupFiles: ['./src/test/setup.ts'],
coverage: {
reporter: ['text', 'json', 'html'],
exclude: [
'node_modules/',
'src/test/',
'**/*.d.ts'
]
}
}
};TypeScript 配置
json
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@utils/*": ["./src/utils/*"],
"@assets/*": ["./src/assets/*"],
"@styles/*": ["./src/styles/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}ESLint 配置
javascript
// .eslintrc.js
module.exports = {
root: true,
env: {
browser: true,
es2020: true,
node: true
},
extends: [
'eslint:recommended',
'@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
'plugin:react/recommended',
'plugin:jsx-a11y/recommended',
'@trae/eslint-config'
],
ignorePatterns: ['dist', '.eslintrc.js'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
ecmaFeatures: {
jsx: true
}
},
plugins: [
'react-refresh',
'@typescript-eslint',
'react',
'react-hooks',
'jsx-a11y'
],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true }
],
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/explicit-function-return-type': 'warn',
'prefer-const': 'error',
'no-var': 'error'
},
settings: {
react: {
version: 'detect'
}
}
};Prettier 配置
json
// .prettierrc
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "avoid",
"endOfLine": "lf"
}环境变量
环境变量文件
Trae 支持多种环境变量文件:
bash
# .env - 所有环境的默认值
VITE_APP_TITLE=My Awesome App
VITE_APP_VERSION=1.0.0
# .env.local - 本地环境(被 git 忽略)
VITE_API_KEY=your-secret-api-key
VITE_DATABASE_URL=postgresql://localhost:5432/myapp
# .env.development - 开发环境
VITE_API_URL=http://localhost:8080/api
VITE_DEBUG=true
VITE_LOG_LEVEL=debug
# .env.production - 生产环境
VITE_API_URL=https://api.myapp.com
VITE_DEBUG=false
VITE_LOG_LEVEL=error
VITE_SENTRY_DSN=https://your-sentry-dsn
# .env.test - 测试环境
VITE_API_URL=http://localhost:3001/api
VITE_TEST_DATABASE_URL=postgresql://localhost:5432/myapp_test环境变量使用
typescript
// src/config/env.ts
interface EnvConfig {
apiUrl: string;
debug: boolean;
logLevel: 'debug' | 'info' | 'warn' | 'error';
version: string;
sentryDsn?: string;
}
export const env: EnvConfig = {
apiUrl: import.meta.env.VITE_API_URL || 'http://localhost:8080/api',
debug: import.meta.env.VITE_DEBUG === 'true',
logLevel: (import.meta.env.VITE_LOG_LEVEL as EnvConfig['logLevel']) || 'info',
version: import.meta.env.VITE_APP_VERSION || '1.0.0',
sentryDsn: import.meta.env.VITE_SENTRY_DSN
};
// 类型安全的环境变量
interface ImportMetaEnv {
readonly VITE_API_URL: string;
readonly VITE_DEBUG: string;
readonly VITE_LOG_LEVEL: string;
readonly VITE_APP_VERSION: string;
readonly VITE_SENTRY_DSN?: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}环境变量验证
typescript
// src/config/validation.ts
import { z } from 'zod';
const envSchema = z.object({
VITE_API_URL: z.string().url(),
VITE_DEBUG: z.enum(['true', 'false']).default('false'),
VITE_LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
VITE_APP_VERSION: z.string().min(1),
VITE_SENTRY_DSN: z.string().url().optional()
});
export function validateEnv(): void {
try {
envSchema.parse(import.meta.env);
} catch (error) {
console.error('❌ Invalid environment variables:', error);
process.exit(1);
}
}
// 在应用启动时调用
validateEnv();构建配置
多环境构建
javascript
// scripts/build.js
import { build } from 'vite';
import { resolve } from 'path';
const environments = ['development', 'staging', 'production'];
async function buildForEnvironment(env) {
console.log(`🏗️ Building for ${env} environment...`);
await build({
mode: env,
build: {
outDir: `dist/${env}`,
sourcemap: env !== 'production',
minify: env === 'production' ? 'terser' : false,
rollupOptions: {
input: {
main: resolve(__dirname, '../index.html'),
admin: resolve(__dirname, '../admin.html')
}
}
},
define: {
__BUILD_TIME__: JSON.stringify(new Date().toISOString()),
__ENVIRONMENT__: JSON.stringify(env)
}
});
console.log(`✅ Build completed for ${env}`);
}
// 构建所有环境
for (const env of environments) {
await buildForEnvironment(env);
}代码分割配置
javascript
// trae.config.js
export default {
build: {
rollupOptions: {
output: {
manualChunks: {
// 将 React 相关库打包到单独的 chunk
react: ['react', 'react-dom'],
// 将路由相关库打包到单独的 chunk
router: ['react-router-dom'],
// 将 UI 库打包到单独的 chunk
ui: ['antd', '@ant-design/icons'],
// 将工具库打包到单独的 chunk
utils: ['lodash', 'dayjs', 'axios'],
// 动态分割大型库
vendor: (id) => {
if (id.includes('node_modules')) {
// 将大于 500KB 的包单独打包
const packageName = id.split('node_modules/')[1].split('/')[0];
const largePackages = ['monaco-editor', 'echarts', 'three'];
if (largePackages.includes(packageName)) {
return packageName;
}
return 'vendor';
}
}
},
// 文件命名策略
chunkFileNames: (chunkInfo) => {
const facadeModuleId = chunkInfo.facadeModuleId
? chunkInfo.facadeModuleId.split('/').pop().replace('.js', '')
: 'chunk';
return `js/${facadeModuleId}-[hash].js`;
},
assetFileNames: (assetInfo) => {
const info = assetInfo.name.split('.');
const ext = info[info.length - 1];
if (/\.(png|jpe?g|gif|svg|webp|ico)$/i.test(assetInfo.name)) {
return `images/[name]-[hash][extname]`;
}
if (/\.(woff2?|eot|ttf|otf)$/i.test(assetInfo.name)) {
return `fonts/[name]-[hash][extname]`;
}
if (/\.(css)$/i.test(assetInfo.name)) {
return `css/[name]-[hash][extname]`;
}
return `assets/[name]-[hash][extname]`;
}
}
}
}
};开发服务器配置
代理配置
javascript
// trae.config.js
export default {
server: {
proxy: {
// 代理 API 请求
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
configure: (proxy, options) => {
proxy.on('error', (err, req, res) => {
console.log('proxy error', err);
});
proxy.on('proxyReq', (proxyReq, req, res) => {
console.log('Sending Request to the Target:', req.method, req.url);
});
proxy.on('proxyRes', (proxyRes, req, res) => {
console.log('Received Response from the Target:', proxyRes.statusCode, req.url);
});
}
},
// 代理 WebSocket
'/ws': {
target: 'ws://localhost:8080',
ws: true,
changeOrigin: true
},
// 代理静态资源
'/uploads': {
target: 'http://localhost:9000',
changeOrigin: true
}
},
// 中间件配置
middlewares: [
// 自定义中间件
(req, res, next) => {
if (req.url === '/api/health') {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ status: 'ok', timestamp: Date.now() }));
return;
}
next();
}
]
}
};热重载配置
javascript
// trae.config.js
export default {
server: {
hmr: {
port: 24678,
overlay: true
},
// 文件监听配置
watch: {
ignored: ['**/node_modules/**', '**/dist/**'],
include: ['src/**/*', 'public/**/*'],
usePolling: false, // 在某些系统上可能需要设置为 true
interval: 100
}
},
// 插件配置
plugins: [
{
name: 'custom-hmr',
handleHotUpdate(ctx) {
// 自定义热更新逻辑
if (ctx.file.endsWith('.env')) {
console.log('Environment file changed, restarting server...');
ctx.server.restart();
return [];
}
if (ctx.file.includes('config')) {
console.log('Config file changed, full reload...');
ctx.server.ws.send({
type: 'full-reload'
});
return [];
}
}
}
]
};插件配置
官方插件
javascript
// trae.config.js
import { defineConfig } from 'trae';
import react from '@trae/plugin-react';
import typescript from '@trae/plugin-typescript';
import pwa from '@trae/plugin-pwa';
import { visualizer } from '@trae/plugin-visualizer';
export default defineConfig({
plugins: [
// React 插件
react({
include: '**/*.{jsx,tsx}',
babel: {
plugins: [
['import', { libraryName: 'antd', style: true }]
]
}
}),
// TypeScript 插件
typescript({
check: true,
include: ['src/**/*'],
exclude: ['node_modules', 'dist']
}),
// PWA 插件
pwa({
registerType: 'autoUpdate',
includeAssets: ['favicon.ico', 'apple-touch-icon.png'],
manifest: {
name: 'My Awesome App',
short_name: 'MyApp',
description: 'A modern web application',
theme_color: '#ffffff',
background_color: '#ffffff',
display: 'standalone',
icons: [
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png'
}
]
},
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
runtimeCaching: [
{
urlPattern: /^https:\/\/api\.myapp\.com\/.*/i,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365 // 1 year
},
cacheableResponse: {
statuses: [0, 200]
}
}
}
]
}
}),
// 构建分析插件
visualizer({
filename: 'dist/stats.html',
open: true,
gzipSize: true,
brotliSize: true
})
]
});自定义插件
javascript
// plugins/custom-plugin.js
export function customPlugin(options = {}) {
return {
name: 'custom-plugin',
// 插件配置
configResolved(config) {
this.isProduction = config.command === 'build';
},
// 构建开始
buildStart(options) {
console.log('🚀 Build started with custom plugin');
},
// 转换代码
transform(code, id) {
if (id.includes('special-file.js')) {
// 自定义代码转换
return {
code: code.replace(/OLD_PATTERN/g, 'NEW_PATTERN'),
map: null
};
}
},
// 生成文件
generateBundle(options, bundle) {
// 生成额外的文件
this.emitFile({
type: 'asset',
fileName: 'build-info.json',
source: JSON.stringify({
buildTime: new Date().toISOString(),
version: process.env.npm_package_version,
environment: process.env.NODE_ENV
}, null, 2)
});
},
// 开发服务器配置
configureServer(server) {
server.middlewares.use('/api/custom', (req, res, next) => {
if (req.method === 'GET') {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ message: 'Custom API endpoint' }));
} else {
next();
}
});
}
};
}性能优化配置
依赖预构建
javascript
// trae.config.js
export default {
optimizeDeps: {
// 强制预构建的依赖
include: [
'react',
'react-dom',
'react-router-dom',
'antd',
'lodash',
'dayjs'
],
// 排除预构建的依赖
exclude: [
'@trae/dev-tools',
'some-esm-only-package'
],
// 自定义 esbuild 选项
esbuildOptions: {
target: 'es2020',
supported: {
'top-level-await': true
}
},
// 强制重新预构建
force: false
},
// 构建优化
build: {
// 启用/禁用 CSS 代码分割
cssCodeSplit: true,
// 构建后是否生成 source map
sourcemap: false,
// chunk 大小警告的限制(以 kbs 为单位)
chunkSizeWarningLimit: 500,
// 自定义底层的 Rollup 打包配置
rollupOptions: {
// 确保外部化处理那些你不想打包进库的依赖
external: ['react', 'react-dom'],
output: {
// 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
globals: {
react: 'React',
'react-dom': 'ReactDOM'
}
}
},
// 自定义构建的 Terser 选项
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
}
};缓存配置
javascript
// trae.config.js
export default {
cacheDir: 'node_modules/.trae',
server: {
// 强制依赖预构建
force: false
},
build: {
// 启用/禁用 gzip 压缩大小报告
reportCompressedSize: false,
// 启用构建缓存
cache: {
type: 'filesystem',
cacheDirectory: 'node_modules/.cache/trae'
}
}
};部署配置
静态部署
javascript
// deploy/static.js
import { execSync } from 'child_process';
import { copyFileSync, mkdirSync } from 'fs';
import { resolve } from 'path';
// 构建项目
execSync('npm run build', { stdio: 'inherit' });
// 复制静态文件
const staticFiles = [
'_redirects',
'_headers',
'robots.txt',
'sitemap.xml'
];
staticFiles.forEach(file => {
try {
copyFileSync(
resolve(`public/${file}`),
resolve(`dist/${file}`)
);
console.log(`✅ Copied ${file}`);
} catch (error) {
console.log(`⚠️ ${file} not found, skipping`);
}
});
console.log('🚀 Static deployment ready!');Docker 配置
dockerfile
# Dockerfile
FROM node:18-alpine as builder
WORKDIR /app
# 复制 package 文件
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制源代码
COPY . .
# 构建应用
RUN npm run build
# 生产镜像
FROM nginx:alpine
# 复制构建结果
COPY --from=builder /app/dist /usr/share/nginx/html
# 复制 nginx 配置
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]nginx
# nginx.conf
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# 启用 gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML 文件不缓存
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# SPA 路由支持
location / {
try_files $uri $uri/ /index.html;
}
# API 代理
location /api/ {
proxy_pass http://backend:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}最佳实践
配置文件组织
project/
├── config/
│ ├── base.config.js # 基础配置
│ ├── development.config.js # 开发环境配置
│ ├── production.config.js # 生产环境配置
│ └── test.config.js # 测试环境配置
├── scripts/
│ ├── build.js # 构建脚本
│ ├── deploy.js # 部署脚本
│ └── dev.js # 开发脚本
└── trae.config.js # 主配置文件配置验证
javascript
// config/validation.js
import Joi from 'joi';
const configSchema = Joi.object({
server: Joi.object({
port: Joi.number().port().default(3000),
host: Joi.string().default('localhost'),
https: Joi.boolean().default(false)
}),
build: Joi.object({
outDir: Joi.string().default('dist'),
sourcemap: Joi.boolean().default(true),
minify: Joi.string().valid('terser', 'esbuild', false).default('terser')
}),
env: Joi.object().pattern(
Joi.string(),
Joi.object().unknown(true)
)
});
export function validateConfig(config) {
const { error, value } = configSchema.validate(config, {
allowUnknown: true,
stripUnknown: false
});
if (error) {
throw new Error(`Configuration validation failed: ${error.message}`);
}
return value;
}配置合并
javascript
// trae.config.js
import { defineConfig, mergeConfig } from 'trae';
import baseConfig from './config/base.config.js';
import { validateConfig } from './config/validation.js';
const envConfigs = {
development: () => import('./config/development.config.js'),
production: () => import('./config/production.config.js'),
test: () => import('./config/test.config.js')
};
export default defineConfig(async ({ command, mode }) => {
// 加载环境特定配置
const envConfig = envConfigs[mode]
? (await envConfigs[mode]()).default
: {};
// 合并配置
const config = mergeConfig(baseConfig, envConfig);
// 验证配置
const validatedConfig = validateConfig(config);
console.log(`🔧 Loaded configuration for ${mode} mode`);
return validatedConfig;
});通过合理的配置管理,您可以确保 Trae 项目在不同环境下都能稳定运行,同时保持良好的开发体验和构建性能。