Skip to content

大型前端项目架构设计

随着前端应用复杂度的不断提升,如何设计一个可扩展、可维护的大型前端项目架构成为了关键挑战。本文将深入探讨前端架构设计的核心原则和实践方法。

架构设计原则

1. 单一职责原则 (SRP)

每个模块、组件或函数都应该有且仅有一个改变的理由。

javascript
// ❌ 违反单一职责原则
class UserManager {
  constructor() {
    this.users = [];
  }
  
  addUser(user) {
    this.users.push(user);
  }
  
  saveToDatabase(user) {
    // 数据库操作
  }
  
  sendEmail(user) {
    // 邮件发送
  }
  
  validateUser(user) {
    // 用户验证
  }
}

// ✅ 遵循单一职责原则
class UserRepository {
  saveUser(user) {
    // 数据库操作
  }
  
  findUser(id) {
    // 查询操作
  }
}

class EmailService {
  sendWelcomeEmail(user) {
    // 邮件发送
  }
}

class UserValidator {
  validate(user) {
    // 用户验证
  }
}

class UserService {
  constructor(repository, emailService, validator) {
    this.repository = repository;
    this.emailService = emailService;
    this.validator = validator;
  }
  
  async createUser(userData) {
    const user = this.validator.validate(userData);
    await this.repository.saveUser(user);
    await this.emailService.sendWelcomeEmail(user);
    return user;
  }
}

2. 开闭原则 (OCP)

软件实体应该对扩展开放,对修改关闭。

javascript
// 策略模式实现开闭原则
class PaymentProcessor {
  constructor(strategy) {
    this.strategy = strategy;
  }
  
  process(amount) {
    return this.strategy.pay(amount);
  }
}

class CreditCardPayment {
  pay(amount) {
    console.log(`Processing $${amount} via Credit Card`);
  }
}

class PayPalPayment {
  pay(amount) {
    console.log(`Processing $${amount} via PayPal`);
  }
}

class AlipayPayment {
  pay(amount) {
    console.log(`Processing $${amount} via Alipay`);
  }
}

// 使用
const processor = new PaymentProcessor(new CreditCardPayment());
processor.process(100);

3. 依赖倒置原则 (DIP)

高层模块不应该依赖低层模块,两者都应该依赖抽象。

javascript
// 依赖注入容器
class DIContainer {
  constructor() {
    this.services = new Map();
  }
  
  register(name, factory) {
    this.services.set(name, factory);
  }
  
  resolve(name) {
    const factory = this.services.get(name);
    if (!factory) {
      throw new Error(`Service ${name} not found`);
    }
    return factory();
  }
}

// 注册服务
const container = new DIContainer();

container.register('apiClient', () => new ApiClient());
container.register('userRepository', () => 
  new UserRepository(container.resolve('apiClient'))
);
container.register('userService', () => 
  new UserService(container.resolve('userRepository'))
);

项目结构设计

1. 分层架构

src/
├── presentation/          # 表现层
│   ├── components/       # 通用组件
│   ├── pages/           # 页面组件
│   ├── layouts/         # 布局组件
│   └── hooks/           # 自定义 Hooks
├── application/          # 应用层
│   ├── services/        # 业务服务
│   ├── stores/          # 状态管理
│   └── use-cases/       # 用例
├── domain/              # 领域层
│   ├── entities/        # 实体
│   ├── repositories/    # 仓储接口
│   └── value-objects/   # 值对象
├── infrastructure/      # 基础设施层
│   ├── api/            # API 客户端
│   ├── storage/        # 存储实现
│   └── external/       # 外部服务
└── shared/             # 共享模块
    ├── utils/          # 工具函数
    ├── constants/      # 常量
    └── types/          # 类型定义

2. 功能模块化

src/
├── modules/
│   ├── auth/
│   │   ├── components/
│   │   ├── services/
│   │   ├── stores/
│   │   ├── types/
│   │   └── index.ts
│   ├── user/
│   │   ├── components/
│   │   ├── services/
│   │   ├── stores/
│   │   ├── types/
│   │   └── index.ts
│   └── product/
│       ├── components/
│       ├── services/
│       ├── stores/
│       ├── types/
│       └── index.ts
└── core/
    ├── api/
    ├── router/
    ├── store/
    └── utils/

组件架构设计

1. 原子设计方法论

components/
├── atoms/              # 原子组件
│   ├── Button/
│   ├── Input/
│   ├── Label/
│   └── Icon/
├── molecules/          # 分子组件
│   ├── SearchBox/
│   ├── FormField/
│   └── Card/
├── organisms/          # 有机体组件
│   ├── Header/
│   ├── ProductList/
│   └── ContactForm/
├── templates/          # 模板
│   ├── PageLayout/
│   └── ArticleLayout/
└── pages/             # 页面
    ├── HomePage/
    ├── ProductPage/
    └── ContactPage/

2. 组件设计模式

容器组件与展示组件分离

jsx
// 展示组件 - 只负责 UI 渲染
const UserList = ({ users, onUserClick, loading }) => {
  if (loading) {
    return <LoadingSpinner />;
  }
  
  return (
    <div className="user-list">
      {users.map(user => (
        <UserCard 
          key={user.id} 
          user={user} 
          onClick={() => onUserClick(user.id)}
        />
      ))}
    </div>
  );
};

// 容器组件 - 负责数据获取和状态管理
const UserListContainer = () => {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    fetchUsers().then(data => {
      setUsers(data);
      setLoading(false);
    });
  }, []);
  
  const handleUserClick = (userId) => {
    navigate(`/users/${userId}`);
  };
  
  return (
    <UserList 
      users={users}
      loading={loading}
      onUserClick={handleUserClick}
    />
  );
};

高阶组件 (HOC) 模式

jsx
// 权限控制 HOC
const withAuth = (WrappedComponent, requiredRole) => {
  return (props) => {
    const { user, loading } = useAuth();
    
    if (loading) {
      return <LoadingSpinner />;
    }
    
    if (!user || !user.roles.includes(requiredRole)) {
      return <AccessDenied />;
    }
    
    return <WrappedComponent {...props} />;
  };
};

// 使用
const AdminPanel = withAuth(AdminPanelComponent, 'admin');

Render Props 模式

jsx
const DataFetcher = ({ url, children }) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    fetch(url)
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      })
      .catch(error => {
        setError(error);
        setLoading(false);
      });
  }, [url]);
  
  return children({ data, loading, error });
};

// 使用
const UserProfile = ({ userId }) => (
  <DataFetcher url={`/api/users/${userId}`}>
    {({ data: user, loading, error }) => {
      if (loading) return <LoadingSpinner />;
      if (error) return <ErrorMessage error={error} />;
      return <UserCard user={user} />;
    }}
  </DataFetcher>
);

状态管理架构

1. 状态分层管理

javascript
// 全局状态 - 使用 Redux/Zustand
const useGlobalStore = create((set, get) => ({
  user: null,
  theme: 'light',
  language: 'zh-CN',
  
  setUser: (user) => set({ user }),
  setTheme: (theme) => set({ theme }),
  setLanguage: (language) => set({ language }),
}));

// 页面级状态 - 使用 Context
const PageContext = createContext();

const PageProvider = ({ children }) => {
  const [pageData, setPageData] = useState(null);
  const [filters, setFilters] = useState({});
  
  return (
    <PageContext.Provider value={{
      pageData,
      filters,
      setPageData,
      setFilters
    }}>
      {children}
    </PageContext.Provider>
  );
};

// 组件级状态 - 使用 useState/useReducer
const ComponentWithLocalState = () => {
  const [localState, setLocalState] = useState(initialState);
  
  return (
    <div>
      {/* 组件内容 */}
    </div>
  );
};

2. 状态管理模式

Flux 架构模式

javascript
// Action Types
const ActionTypes = {
  FETCH_USERS_REQUEST: 'FETCH_USERS_REQUEST',
  FETCH_USERS_SUCCESS: 'FETCH_USERS_SUCCESS',
  FETCH_USERS_FAILURE: 'FETCH_USERS_FAILURE',
};

// Action Creators
const fetchUsersRequest = () => ({
  type: ActionTypes.FETCH_USERS_REQUEST
});

const fetchUsersSuccess = (users) => ({
  type: ActionTypes.FETCH_USERS_SUCCESS,
  payload: users
});

const fetchUsersFailure = (error) => ({
  type: ActionTypes.FETCH_USERS_FAILURE,
  payload: error
});

// Async Action Creator (Thunk)
const fetchUsers = () => async (dispatch) => {
  dispatch(fetchUsersRequest());
  
  try {
    const users = await userService.getUsers();
    dispatch(fetchUsersSuccess(users));
  } catch (error) {
    dispatch(fetchUsersFailure(error.message));
  }
};

// Reducer
const usersReducer = (state = initialState, action) => {
  switch (action.type) {
    case ActionTypes.FETCH_USERS_REQUEST:
      return {
        ...state,
        loading: true,
        error: null
      };
    
    case ActionTypes.FETCH_USERS_SUCCESS:
      return {
        ...state,
        loading: false,
        users: action.payload
      };
    
    case ActionTypes.FETCH_USERS_FAILURE:
      return {
        ...state,
        loading: false,
        error: action.payload
      };
    
    default:
      return state;
  }
};

API 层架构

1. API 客户端设计

javascript
class ApiClient {
  constructor(baseURL, options = {}) {
    this.baseURL = baseURL;
    this.options = options;
    this.interceptors = {
      request: [],
      response: []
    };
  }
  
  // 请求拦截器
  addRequestInterceptor(interceptor) {
    this.interceptors.request.push(interceptor);
  }
  
  // 响应拦截器
  addResponseInterceptor(interceptor) {
    this.interceptors.response.push(interceptor);
  }
  
  async request(config) {
    // 应用请求拦截器
    let requestConfig = { ...config };
    for (const interceptor of this.interceptors.request) {
      requestConfig = await interceptor(requestConfig);
    }
    
    try {
      let response = await fetch(`${this.baseURL}${requestConfig.url}`, {
        method: requestConfig.method || 'GET',
        headers: {
          'Content-Type': 'application/json',
          ...this.options.headers,
          ...requestConfig.headers
        },
        body: requestConfig.data ? JSON.stringify(requestConfig.data) : undefined
      });
      
      // 应用响应拦截器
      for (const interceptor of this.interceptors.response) {
        response = await interceptor(response);
      }
      
      return response;
    } catch (error) {
      throw new ApiError(error.message, error.status);
    }
  }
  
  get(url, config = {}) {
    return this.request({ ...config, method: 'GET', url });
  }
  
  post(url, data, config = {}) {
    return this.request({ ...config, method: 'POST', url, data });
  }
  
  put(url, data, config = {}) {
    return this.request({ ...config, method: 'PUT', url, data });
  }
  
  delete(url, config = {}) {
    return this.request({ ...config, method: 'DELETE', url });
  }
}

// API 错误类
class ApiError extends Error {
  constructor(message, status, data) {
    super(message);
    this.name = 'ApiError';
    this.status = status;
    this.data = data;
  }
}

2. 资源层抽象

javascript
// 基础资源类
class BaseResource {
  constructor(apiClient, endpoint) {
    this.apiClient = apiClient;
    this.endpoint = endpoint;
  }
  
  async findAll(params = {}) {
    const response = await this.apiClient.get(this.endpoint, { params });
    return response.data;
  }
  
  async findById(id) {
    const response = await this.apiClient.get(`${this.endpoint}/${id}`);
    return response.data;
  }
  
  async create(data) {
    const response = await this.apiClient.post(this.endpoint, data);
    return response.data;
  }
  
  async update(id, data) {
    const response = await this.apiClient.put(`${this.endpoint}/${id}`, data);
    return response.data;
  }
  
  async delete(id) {
    await this.apiClient.delete(`${this.endpoint}/${id}`);
  }
}

// 具体资源类
class UserResource extends BaseResource {
  constructor(apiClient) {
    super(apiClient, '/users');
  }
  
  async findByEmail(email) {
    const response = await this.apiClient.get(`${this.endpoint}/by-email`, {
      params: { email }
    });
    return response.data;
  }
  
  async updateProfile(id, profileData) {
    const response = await this.apiClient.put(
      `${this.endpoint}/${id}/profile`, 
      profileData
    );
    return response.data;
  }
}

// API 服务工厂
class ApiService {
  constructor(baseURL) {
    this.apiClient = new ApiClient(baseURL);
    
    // 添加认证拦截器
    this.apiClient.addRequestInterceptor(async (config) => {
      const token = localStorage.getItem('authToken');
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
      return config;
    });
    
    // 添加错误处理拦截器
    this.apiClient.addResponseInterceptor(async (response) => {
      if (!response.ok) {
        const error = await response.json();
        throw new ApiError(error.message, response.status, error);
      }
      return response.json();
    });
    
    // 初始化资源
    this.users = new UserResource(this.apiClient);
    this.products = new BaseResource(this.apiClient, '/products');
    this.orders = new BaseResource(this.apiClient, '/orders');
  }
}

路由架构

1. 路由配置

javascript
// 路由配置
const routes = [
  {
    path: '/',
    component: HomeLayout,
    children: [
      {
        path: '',
        component: HomePage,
        meta: { title: '首页' }
      },
      {
        path: 'about',
        component: AboutPage,
        meta: { title: '关于我们' }
      }
    ]
  },
  {
    path: '/auth',
    component: AuthLayout,
    children: [
      {
        path: 'login',
        component: LoginPage,
        meta: { title: '登录', requiresGuest: true }
      },
      {
        path: 'register',
        component: RegisterPage,
        meta: { title: '注册', requiresGuest: true }
      }
    ]
  },
  {
    path: '/dashboard',
    component: DashboardLayout,
    meta: { requiresAuth: true },
    children: [
      {
        path: '',
        component: DashboardHome,
        meta: { title: '控制台' }
      },
      {
        path: 'users',
        component: UserManagement,
        meta: { title: '用户管理', requiredRole: 'admin' }
      }
    ]
  }
];

// 路由守卫
const router = createRouter({
  history: createWebHistory(),
  routes
});

router.beforeEach(async (to, from, next) => {
  // 设置页面标题
  if (to.meta.title) {
    document.title = `${to.meta.title} - 应用名称`;
  }
  
  // 认证检查
  if (to.meta.requiresAuth) {
    const isAuthenticated = await checkAuth();
    if (!isAuthenticated) {
      return next('/auth/login');
    }
  }
  
  // 访客页面检查
  if (to.meta.requiresGuest) {
    const isAuthenticated = await checkAuth();
    if (isAuthenticated) {
      return next('/dashboard');
    }
  }
  
  // 角色权限检查
  if (to.meta.requiredRole) {
    const user = await getCurrentUser();
    if (!user || !user.roles.includes(to.meta.requiredRole)) {
      return next('/403');
    }
  }
  
  next();
});

2. 代码分割与懒加载

javascript
// 路由级代码分割
const routes = [
  {
    path: '/',
    component: () => import('../pages/HomePage.vue')
  },
  {
    path: '/dashboard',
    component: () => import('../pages/DashboardPage.vue'),
    children: [
      {
        path: 'users',
        component: () => import('../pages/UserManagement.vue')
      },
      {
        path: 'products',
        component: () => import('../pages/ProductManagement.vue')
      }
    ]
  }
];

// 预加载策略
const preloadRoute = (routeName) => {
  const route = routes.find(r => r.name === routeName);
  if (route && typeof route.component === 'function') {
    route.component();
  }
};

// 在用户交互时预加载
const handleMouseEnter = () => {
  preloadRoute('dashboard');
};

性能优化架构

1. 缓存策略

javascript
// 内存缓存
class MemoryCache {
  constructor(maxSize = 100, ttl = 5 * 60 * 1000) {
    this.cache = new Map();
    this.maxSize = maxSize;
    this.ttl = ttl;
  }
  
  set(key, value) {
    if (this.cache.size >= this.maxSize) {
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }
    
    this.cache.set(key, {
      value,
      timestamp: Date.now()
    });
  }
  
  get(key) {
    const item = this.cache.get(key);
    if (!item) return null;
    
    if (Date.now() - item.timestamp > this.ttl) {
      this.cache.delete(key);
      return null;
    }
    
    return item.value;
  }
  
  clear() {
    this.cache.clear();
  }
}

// HTTP 缓存
class HttpCache {
  constructor() {
    this.cache = new MemoryCache();
  }
  
  generateKey(url, params) {
    return `${url}?${new URLSearchParams(params).toString()}`;
  }
  
  async get(url, params = {}) {
    const key = this.generateKey(url, params);
    const cached = this.cache.get(key);
    
    if (cached) {
      return cached;
    }
    
    const response = await fetch(url + '?' + new URLSearchParams(params));
    const data = await response.json();
    
    this.cache.set(key, data);
    return data;
  }
}

2. 虚拟化列表

jsx
// 虚拟化列表组件
const VirtualList = ({ 
  items, 
  itemHeight, 
  containerHeight, 
  renderItem 
}) => {
  const [scrollTop, setScrollTop] = useState(0);
  
  const visibleStart = Math.floor(scrollTop / itemHeight);
  const visibleEnd = Math.min(
    visibleStart + Math.ceil(containerHeight / itemHeight) + 1,
    items.length
  );
  
  const visibleItems = items.slice(visibleStart, visibleEnd);
  
  const handleScroll = (e) => {
    setScrollTop(e.target.scrollTop);
  };
  
  return (
    <div 
      style={{ height: containerHeight, overflow: 'auto' }}
      onScroll={handleScroll}
    >
      <div style={{ height: items.length * itemHeight, position: 'relative' }}>
        {visibleItems.map((item, index) => (
          <div
            key={visibleStart + index}
            style={{
              position: 'absolute',
              top: (visibleStart + index) * itemHeight,
              height: itemHeight,
              width: '100%'
            }}
          >
            {renderItem(item, visibleStart + index)}
          </div>
        ))}
      </div>
    </div>
  );
};

错误处理架构

1. 全局错误处理

javascript
// 错误边界组件
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
  
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }
  
  componentDidCatch(error, errorInfo) {
    // 记录错误到监控服务
    errorReportingService.captureException(error, {
      extra: errorInfo,
      tags: {
        component: 'ErrorBoundary'
      }
    });
  }
  
  render() {
    if (this.state.hasError) {
      return this.props.fallback || <ErrorFallback error={this.state.error} />;
    }
    
    return this.props.children;
  }
}

// 错误报告服务
class ErrorReportingService {
  constructor(config) {
    this.config = config;
    this.queue = [];
    this.isOnline = navigator.onLine;
    
    window.addEventListener('online', () => {
      this.isOnline = true;
      this.flushQueue();
    });
    
    window.addEventListener('offline', () => {
      this.isOnline = false;
    });
  }
  
  captureException(error, context = {}) {
    const errorReport = {
      message: error.message,
      stack: error.stack,
      timestamp: new Date().toISOString(),
      url: window.location.href,
      userAgent: navigator.userAgent,
      ...context
    };
    
    if (this.isOnline) {
      this.sendReport(errorReport);
    } else {
      this.queue.push(errorReport);
    }
  }
  
  async sendReport(report) {
    try {
      await fetch(this.config.endpoint, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${this.config.apiKey}`
        },
        body: JSON.stringify(report)
      });
    } catch (error) {
      console.error('Failed to send error report:', error);
    }
  }
  
  flushQueue() {
    while (this.queue.length > 0) {
      const report = this.queue.shift();
      this.sendReport(report);
    }
  }
}

2. 异步错误处理

javascript
// 异步操作包装器
const withErrorHandling = (asyncFn) => {
  return async (...args) => {
    try {
      return await asyncFn(...args);
    } catch (error) {
      errorReportingService.captureException(error, {
        function: asyncFn.name,
        arguments: args
      });
      throw error;
    }
  };
};

// 使用示例
const fetchUserData = withErrorHandling(async (userId) => {
  const response = await apiService.users.findById(userId);
  return response;
});

// Promise 错误处理
const handleAsyncError = (promise) => {
  return promise.catch(error => {
    errorReportingService.captureException(error);
    return { error: error.message };
  });
};

测试架构

1. 测试金字塔

javascript
// 单元测试
describe('UserService', () => {
  let userService;
  let mockRepository;
  
  beforeEach(() => {
    mockRepository = {
      findById: jest.fn(),
      save: jest.fn()
    };
    userService = new UserService(mockRepository);
  });
  
  test('should create user successfully', async () => {
    const userData = { name: 'John', email: 'john@example.com' };
    const expectedUser = { id: 1, ...userData };
    
    mockRepository.save.mockResolvedValue(expectedUser);
    
    const result = await userService.createUser(userData);
    
    expect(mockRepository.save).toHaveBeenCalledWith(userData);
    expect(result).toEqual(expectedUser);
  });
});

// 集成测试
describe('User API Integration', () => {
  test('should create and retrieve user', async () => {
    const userData = { name: 'John', email: 'john@example.com' };
    
    // 创建用户
    const createResponse = await request(app)
      .post('/api/users')
      .send(userData)
      .expect(201);
    
    const userId = createResponse.body.id;
    
    // 获取用户
    const getResponse = await request(app)
      .get(`/api/users/${userId}`)
      .expect(200);
    
    expect(getResponse.body).toMatchObject(userData);
  });
});

// E2E 测试
describe('User Registration Flow', () => {
  test('should complete user registration', async () => {
    await page.goto('/register');
    
    await page.fill('[data-testid="name-input"]', 'John Doe');
    await page.fill('[data-testid="email-input"]', 'john@example.com');
    await page.fill('[data-testid="password-input"]', 'password123');
    
    await page.click('[data-testid="register-button"]');
    
    await expect(page).toHaveURL('/dashboard');
    await expect(page.locator('[data-testid="welcome-message"]'))
      .toContainText('Welcome, John Doe');
  });
});

部署架构

1. 构建优化

javascript
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production';
  
  return {
    entry: {
      main: './src/index.js',
      vendor: ['react', 'react-dom', 'lodash']
    },
    
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: isProduction 
        ? '[name].[contenthash].js' 
        : '[name].js',
      chunkFilename: isProduction 
        ? '[name].[contenthash].chunk.js' 
        : '[name].chunk.js',
      clean: true
    },
    
    optimization: {
      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            chunks: 'all',
          },
          common: {
            name: 'common',
            minChunks: 2,
            chunks: 'all',
            enforce: true
          }
        }
      }
    },
    
    plugins: [
      new HtmlWebpackPlugin({
        template: './public/index.html',
        minify: isProduction
      }),
      
      new MiniCssExtractPlugin({
        filename: isProduction 
          ? '[name].[contenthash].css' 
          : '[name].css'
      }),
      
      ...(process.env.ANALYZE ? [new BundleAnalyzerPlugin()] : [])
    ]
  };
};

2. 环境配置

javascript
// 环境配置管理
class ConfigManager {
  constructor() {
    this.env = process.env.NODE_ENV || 'development';
    this.config = this.loadConfig();
  }
  
  loadConfig() {
    const baseConfig = {
      app: {
        name: 'MyApp',
        version: process.env.npm_package_version
      }
    };
    
    const envConfig = {
      development: {
        api: {
          baseURL: 'http://localhost:3001/api',
          timeout: 10000
        },
        features: {
          debugMode: true,
          mockData: true
        }
      },
      
      staging: {
        api: {
          baseURL: 'https://staging-api.example.com/api',
          timeout: 15000
        },
        features: {
          debugMode: false,
          mockData: false
        }
      },
      
      production: {
        api: {
          baseURL: 'https://api.example.com/api',
          timeout: 15000
        },
        features: {
          debugMode: false,
          mockData: false
        }
      }
    };
    
    return {
      ...baseConfig,
      ...envConfig[this.env]
    };
  }
  
  get(path) {
    return path.split('.').reduce((obj, key) => obj?.[key], this.config);
  }
}

export const config = new ConfigManager();

监控与日志

1. 性能监控

javascript
// 性能监控服务
class PerformanceMonitor {
  constructor() {
    this.metrics = new Map();
    this.observers = [];
    this.initObservers();
  }
  
  initObservers() {
    // 页面加载性能
    if ('PerformanceObserver' in window) {
      const observer = new PerformanceObserver((list) => {
        for (const entry of list.getEntries()) {
          this.recordMetric(entry.name, entry.duration);
        }
      });
      
      observer.observe({ entryTypes: ['navigation', 'paint', 'largest-contentful-paint'] });
      this.observers.push(observer);
    }
    
    // 资源加载性能
    const resourceObserver = new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        if (entry.duration > 1000) { // 超过1秒的资源
          this.recordSlowResource(entry);
        }
      }
    });
    
    resourceObserver.observe({ entryTypes: ['resource'] });
    this.observers.push(resourceObserver);
  }
  
  recordMetric(name, value, tags = {}) {
    const metric = {
      name,
      value,
      timestamp: Date.now(),
      tags
    };
    
    this.metrics.set(`${name}_${Date.now()}`, metric);
    this.sendMetric(metric);
  }
  
  recordSlowResource(entry) {
    this.recordMetric('slow_resource', entry.duration, {
      url: entry.name,
      type: entry.initiatorType
    });
  }
  
  async sendMetric(metric) {
    try {
      await fetch('/api/metrics', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(metric)
      });
    } catch (error) {
      console.warn('Failed to send metric:', error);
    }
  }
  
  // 自定义性能标记
  mark(name) {
    performance.mark(name);
  }
  
  measure(name, startMark, endMark) {
    performance.measure(name, startMark, endMark);
    const measure = performance.getEntriesByName(name, 'measure')[0];
    this.recordMetric(name, measure.duration);
  }
}

export const performanceMonitor = new PerformanceMonitor();

2. 日志系统

javascript
// 日志服务
class Logger {
  constructor(config = {}) {
    this.level = config.level || 'info';
    this.transports = config.transports || [new ConsoleTransport()];
    this.context = config.context || {};
  }
  
  log(level, message, meta = {}) {
    if (!this.shouldLog(level)) return;
    
    const logEntry = {
      level,
      message,
      timestamp: new Date().toISOString(),
      context: { ...this.context, ...meta }
    };
    
    this.transports.forEach(transport => {
      transport.log(logEntry);
    });
  }
  
  debug(message, meta) { this.log('debug', message, meta); }
  info(message, meta) { this.log('info', message, meta); }
  warn(message, meta) { this.log('warn', message, meta); }
  error(message, meta) { this.log('error', message, meta); }
  
  shouldLog(level) {
    const levels = ['debug', 'info', 'warn', 'error'];
    return levels.indexOf(level) >= levels.indexOf(this.level);
  }
  
  child(context) {
    return new Logger({
      level: this.level,
      transports: this.transports,
      context: { ...this.context, ...context }
    });
  }
}

// 控制台传输器
class ConsoleTransport {
  log(entry) {
    const { level, message, timestamp, context } = entry;
    const contextStr = Object.keys(context).length > 0 
      ? JSON.stringify(context) 
      : '';
    
    console[level](`[${timestamp}] ${level.toUpperCase()}: ${message}`, contextStr);
  }
}

// 远程传输器
class RemoteTransport {
  constructor(endpoint) {
    this.endpoint = endpoint;
    this.buffer = [];
    this.flushInterval = setInterval(() => this.flush(), 5000);
  }
  
  log(entry) {
    this.buffer.push(entry);
    
    if (this.buffer.length >= 10) {
      this.flush();
    }
  }
  
  async flush() {
    if (this.buffer.length === 0) return;
    
    const logs = [...this.buffer];
    this.buffer = [];
    
    try {
      await fetch(this.endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ logs })
      });
    } catch (error) {
      console.error('Failed to send logs:', error);
      // 重新加入缓冲区
      this.buffer.unshift(...logs);
    }
  }
}

export const logger = new Logger({
  level: process.env.NODE_ENV === 'production' ? 'warn' : 'debug',
  transports: [
    new ConsoleTransport(),
    ...(process.env.NODE_ENV === 'production' 
      ? [new RemoteTransport('/api/logs')] 
      : [])
  ]
});

安全架构

1. 输入验证与清理

javascript
// 输入验证器
class InputValidator {
  static email(value) {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(value);
  }
  
  static password(value) {
    // 至少8位,包含大小写字母、数字和特殊字符
    const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
    return passwordRegex.test(value);
  }
  
  static sanitizeHtml(html) {
    const div = document.createElement('div');
    div.textContent = html;
    return div.innerHTML;
  }
  
  static validateSchema(data, schema) {
    const errors = [];
    
    for (const [field, rules] of Object.entries(schema)) {
      const value = data[field];
      
      if (rules.required && (value === undefined || value === null || value === '')) {
        errors.push(`${field} is required`);
        continue;
      }
      
      if (value !== undefined && rules.type && typeof value !== rules.type) {
        errors.push(`${field} must be of type ${rules.type}`);
      }
      
      if (rules.minLength && value.length < rules.minLength) {
        errors.push(`${field} must be at least ${rules.minLength} characters`);
      }
      
      if (rules.maxLength && value.length > rules.maxLength) {
        errors.push(`${field} must be no more than ${rules.maxLength} characters`);
      }
      
      if (rules.pattern && !rules.pattern.test(value)) {
        errors.push(`${field} format is invalid`);
      }
      
      if (rules.custom && !rules.custom(value)) {
        errors.push(`${field} validation failed`);
      }
    }
    
    return {
      isValid: errors.length === 0,
      errors
    };
  }
}

// 使用示例
const userSchema = {
  email: {
    required: true,
    type: 'string',
    pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
  },
  password: {
    required: true,
    type: 'string',
    minLength: 8,
    custom: InputValidator.password
  },
  age: {
    type: 'number',
    min: 18,
    max: 120
  }
};

const validation = InputValidator.validateSchema(userData, userSchema);

2. 权限控制

javascript
// 权限管理系统
class PermissionManager {
  constructor() {
    this.permissions = new Map();
    this.roles = new Map();
  }
  
  definePermission(name, description) {
    this.permissions.set(name, { name, description });
  }
  
  defineRole(name, permissions) {
    this.roles.set(name, { name, permissions });
  }
  
  hasPermission(userRoles, requiredPermission) {
    return userRoles.some(role => {
      const roleData = this.roles.get(role);
      return roleData && roleData.permissions.includes(requiredPermission);
    });
  }
  
  checkAccess(user, resource, action) {
    const permission = `${resource}:${action}`;
    return this.hasPermission(user.roles, permission);
  }
}

// 权限装饰器
const requirePermission = (permission) => {
  return (target, propertyKey, descriptor) => {
    const originalMethod = descriptor.value;
    
    descriptor.value = function(...args) {
      const user = this.getCurrentUser();
      
      if (!permissionManager.hasPermission(user.roles, permission)) {
        throw new Error('Access denied: insufficient permissions');
      }
      
      return originalMethod.apply(this, args);
    };
    
    return descriptor;
  };
};

// 使用示例
class UserService {
  @requirePermission('user:read')
  getUsers() {
    return this.userRepository.findAll();
  }
  
  @requirePermission('user:write')
  createUser(userData) {
    return this.userRepository.create(userData);
  }
  
  @requirePermission('user:delete')
  deleteUser(userId) {
    return this.userRepository.delete(userId);
  }
}

国际化架构

javascript
// 国际化管理器
class I18nManager {
  constructor(defaultLocale = 'zh-CN') {
    this.currentLocale = defaultLocale;
    this.messages = new Map();
    this.fallbackLocale = 'en-US';
  }
  
  async loadMessages(locale) {
    if (this.messages.has(locale)) {
      return this.messages.get(locale);
    }
    
    try {
      const messages = await import(`../locales/${locale}.json`);
      this.messages.set(locale, messages.default);
      return messages.default;
    } catch (error) {
      console.warn(`Failed to load messages for locale: ${locale}`);
      return {};
    }
  }
  
  async setLocale(locale) {
    await this.loadMessages(locale);
    this.currentLocale = locale;
    
    // 更新 HTML lang 属性
    document.documentElement.lang = locale;
    
    // 触发语言变更事件
    window.dispatchEvent(new CustomEvent('localechange', {
      detail: { locale }
    }));
  }
  
  t(key, params = {}) {
    const messages = this.messages.get(this.currentLocale) || {};
    const fallbackMessages = this.messages.get(this.fallbackLocale) || {};
    
    let message = this.getNestedValue(messages, key) || 
                  this.getNestedValue(fallbackMessages, key) || 
                  key;
    
    // 参数替换
    Object.entries(params).forEach(([param, value]) => {
      message = message.replace(new RegExp(`{{${param}}}`, 'g'), value);
    });
    
    return message;
  }
  
  getNestedValue(obj, path) {
    return path.split('.').reduce((current, key) => current?.[key], obj);
  }
  
  // 数字格式化
  formatNumber(number, options = {}) {
    return new Intl.NumberFormat(this.currentLocale, options).format(number);
  }
  
  // 日期格式化
  formatDate(date, options = {}) {
    return new Intl.DateTimeFormat(this.currentLocale, options).format(date);
  }
  
  // 货币格式化
  formatCurrency(amount, currency = 'CNY') {
    return new Intl.NumberFormat(this.currentLocale, {
      style: 'currency',
      currency
    }).format(amount);
  }
}

export const i18n = new I18nManager();

总结

大型前端项目架构设计需要考虑多个维度:

核心原则

  1. 模块化设计:清晰的职责分离和依赖管理
  2. 可扩展性:支持功能和团队规模的增长
  3. 可维护性:代码结构清晰,易于理解和修改
  4. 性能优化:从架构层面考虑性能问题
  5. 安全性:内置安全机制和最佳实践

关键技术

  • 分层架构:表现层、应用层、领域层、基础设施层
  • 组件化:原子设计方法论和组件复用
  • 状态管理:合理的状态分层和管理策略
  • 路由设计:代码分割和权限控制
  • API 设计:统一的接口抽象和错误处理

工程化实践

  • 构建优化:代码分割、缓存策略、性能监控
  • 测试策略:单元测试、集成测试、E2E 测试
  • 部署流程:环境配置、CI/CD 集成
  • 监控体系:性能监控、错误追踪、日志管理

通过合理的架构设计,可以构建出高质量、可维护的大型前端应用。

参考资源

vitepress开发指南