前端进阶实战:工程化架构、性能优化与复杂状态管理

29 阅读8分钟

前端进阶实战:工程化架构、性能优化与复杂状态管理

引言

当你已经熟练掌握了HTML/CSS/JavaScript和主流框架的基础用法后,真正的挑战才刚刚开始。中级前端开发者面临的问题不再是“怎么写组件”,而是“如何设计一套可持续演进的架构”、“如何让应用在复杂场景下依然流畅”、“如何构建高效的团队协作流程”。

本文将从工程化架构设计、运行时性能优化、复杂状态管理、微前端实践四个维度展开,全部配有可直接落地的代码示例。


一、工程化架构设计:从“能跑”到“好维护”

1.1 分层架构:让代码各司其职

很多项目失败的根本原因是所有逻辑都堆在组件里。一个健康的项目应该有清晰的分层:

src/
├── api/               # 接口请求层
│   └── user.ts
├── components/        # 通用UI组件(无业务逻辑)
│   └── Button/
├── features/          # 业务模块(按功能域划分)
│   ├── auth/
│   │   ├── components/
│   │   ├── hooks/
│   │   ├── services/
│   │   └── store/
│   └── dashboard/
├── hooks/             # 通用自定义Hooks
├── utils/             # 纯工具函数
├── constants/         # 常量定义
└── types/             # TypeScript类型定义

以React + TypeScript为例,一个规范的数据请求层应该是这样的:

// api/user.ts - 接口层只负责HTTP通信,不处理业务逻辑
import { http } from '@/utils/http';
import type { User, UserListParams, ApiResponse } from '@/types';

export const userApi = {
  // 获取用户列表
  getList: (params: UserListParams): Promise<ApiResponse<User[]>> => {
    return http.get('/api/users', { params });
  },

  // 获取用户详情
  getDetail: (id: string): Promise<ApiResponse<User>> => {
    return http.get(`/api/users/${id}`);
  },

  // 更新用户信息
  update: (id: string, data: Partial<User>): Promise<ApiResponse<User>> => {
    return http.put(`/api/users/${id}`, data);
  }
};
// features/auth/services/login.ts - 业务层处理业务逻辑,调用接口层
import { userApi } from '@/api/user';
import { storage } from '@/utils/storage';
import { trackEvent } from '@/utils/analytics';

export const loginService = {
  async loginWithPassword(username: string, password: string) {
    // 业务逻辑:参数校验、加密、调用接口、处理结果
    if (!username || !password) {
      throw new Error('用户名和密码不能为空');
    }

    const response = await userApi.login({ username, password });

    // 业务逻辑:存储token、记录日志
    storage.set('token', response.data.token);
    trackEvent('login_success', { username });

    return response.data.user;
  },

  async logout() {
    storage.remove('token');
    trackEvent('logout');
  }
};

关键原则:

  • 组件层永远不直接调用fetch或axios,只通过hooks或services间接调用
  • 接口层不关心业务逻辑,只做HTTP通信和数据格式转换
  • 业务层负责组合接口、处理错误、管理副作用

1.2 依赖注入:解决跨层依赖问题

当业务复杂后,组件之间、模块之间会产生大量隐式依赖。使用依赖注入可以让代码更可测试、可维护。

// 使用React Context实现轻量级依赖注入
import { createContext, useContext, type ReactNode } from 'react';

// 定义服务接口
interface LoggerService {
  info: (message: string) => void;
  error: (message: string, error?: unknown) => void;
}

interface AnalyticsService {
  track: (event: string, data?: Record<string, unknown>) => void;
}

// 创建服务容器
interface ServiceContainer {
  logger: LoggerService;
  analytics: AnalyticsService;
}

const ServiceContext = createContext<ServiceContainer | null>(null);

// 服务提供者
export const ServiceProvider = ({ children }: { children: ReactNode }) => {
  const services: ServiceContainer = {
    logger: {
      info: (message) => console.log(`[INFO] ${message}`),
      error: (message, error) => console.error(`[ERROR] ${message}`, error)
    },
    analytics: {
      track: (event, data) => {
        // 实际项目中这里会调用埋点SDK
        console.log(`[TRACK] ${event}`, data);
      }
    }
  };

  return (
    <ServiceContext.Provider value={services}>
      {children}
    </ServiceContext.Provider>
  );
};

// 自定义Hook:获取服务
export const useServices = () => {
  const context = useContext(ServiceContext);
  if (!context) {
    throw new Error('useServices must be used within ServiceProvider');
  }
  return context;
};

// 在组件中使用
const UserProfile = () => {
  const { logger, analytics } = useServices();

  const handleClick = () => {
    logger.info('User profile clicked');
    analytics.track('profile_click');
  };

  return <button onClick={handleClick}>查看资料</button>;
};

这样做的好处是:测试时可以轻松替换mock服务,而不需要修改业务代码。

// 测试时注入mock服务
import { render } from '@testing-library/react';
import { ServiceProvider } from '@/providers/ServiceProvider';

const mockServices = {
  logger: { info: jest.fn(), error: jest.fn() },
  analytics: { track: jest.fn() }
};

render(
  <ServiceProvider services={mockServices}>
    <UserProfile />
  </ServiceProvider>
);

二、运行时性能优化:让应用丝滑如初

2.1 React渲染性能:从根源解决问题

React应用的性能瓶颈通常不在于DOM操作,而在于不必要的重复渲染。我们来看一个典型的性能陷阱:

// ❌ 性能陷阱:父组件每次渲染,子组件也跟着渲染
const Parent = () => {
  const [count, setCount] = useState(0);

  // 这个对象每次渲染都是新引用
  const config = {
    theme: 'dark',
    fontSize: 14
  };

  // 这个函数每次渲染都是新引用
  const handleClick = () => {
    console.log('clicked');
  };

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Count: {count}</button>
      <ExpensiveChild config={config} onAction={handleClick} />
    </div>
  );
};

const ExpensiveChild = ({ config, onAction }) => {
  // 这里会有大量计算
  const processedData = useMemo(() => {
    // 模拟复杂计算
    return heavyComputation(config);
  }, [config]); // config引用每次变,useMemo失效

  return <div onClick={onAction}>{processedData}</div>;
};

解决方案:

// ✅ 正确做法:使用useCallback和useMemo稳定引用
const Parent = () => {
  const [count, setCount] = useState(0);

  // 使用useMemo缓存对象
  const config = useMemo(() => ({
    theme: 'dark',
    fontSize: 14
  }), []); // 空依赖数组,永远不变

  // 使用useCallback缓存函数
  const handleClick = useCallback(() => {
    console.log('clicked');
  }, []);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Count: {count}</button>
      <ExpensiveChild config={config} onAction={handleClick} />
    </div>
  );
};

// 使用React.memo包裹子组件
const ExpensiveChild = memo(({ config, onAction }) => {
  const processedData = useMemo(() => {
    return heavyComputation(config);
  }, [config]);

  return <div onClick={onAction}>{processedData}</div>;
});

2.2 大数据量渲染:虚拟列表实战

当需要渲染成千上万条数据时,直接渲染DOM会导致页面卡死。虚拟列表是解决方案。

// 完整虚拟列表实现 - 支持动态高度
import { useState, useEffect, useRef, useCallback } from 'react';

interface VirtualListProps<T> {
  items: T[];
  estimateHeight?: number; // 预估高度
  overscan?: number;       // 额外渲染的缓冲条数
  renderItem: (item: T, index: number) => React.ReactNode;
}

const VirtualList = <T,>({
  items,
  estimateHeight = 40,
  overscan = 5,
  renderItem
}: VirtualListProps<T>) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const [scrollTop, setScrollTop] = useState(0);
  const [containerHeight, setContainerHeight] = useState(0);

  // 记录每个item的实际位置(处理动态高度)
  const positionsRef = useRef<number[]>([]);

  // 计算每个item的累积高度
  const getItemPosition = useCallback((index: number) => {
    if (positionsRef.current[index] !== undefined) {
      return positionsRef.current[index];
    }
    // 如果还没测量过,使用预估高度
    const lastPosition = positionsRef.current[index - 1] ?? 0;
    return lastPosition + estimateHeight;
  }, [estimateHeight]);

  // 计算总高度
  const totalHeight = items.length * estimateHeight;

  // 计算可见范围
  const startIndex = Math.max(0, Math.floor(scrollTop / estimateHeight) - overscan);
  const endIndex = Math.min(
    items.length,
    Math.ceil((scrollTop + containerHeight) / estimateHeight) + overscan
  );

  // 生成可见数据
  const visibleItems = items.slice(startIndex, endIndex);

  // 监听容器尺寸变化
  useEffect(() => {
    if (!containerRef.current) return;

    const resizeObserver = new ResizeObserver((entries) => {
      setContainerHeight(entries[0].contentRect.height);
    });

    resizeObserver.observe(containerRef.current);
    return () => resizeObserver.disconnect();
  }, []);

  // 测量真实高度
  const measureItem = useCallback((index: number, height: number) => {
    positionsRef.current[index] = height;
  }, []);

  return (
    <div
      ref={containerRef}
      onScroll={(e) => setScrollTop(e.currentTarget.scrollTop)}
      style={{
        height: '100%',
        overflowY: 'auto',
        position: 'relative'
      }}
    >
      {/* 撑起滚动空间的占位元素 */}
      <div style={{ height: totalHeight, position: 'relative' }}>
        {visibleItems.map((item, offset) => {
          const index = startIndex + offset;
          const top = getItemPosition(index);

          return (
            <div
              key={index}
              style={{
                position: 'absolute',
                top,
                left: 0,
                right: 0,
                transform: 'translateY(0)'
              }}
              ref={(el) => {
                if (el) {
                  measureItem(index, el.offsetHeight);
                }
              }}
            >
              {renderItem(item, index)}
            </div>
          );
        })}
      </div>
    </div>
  );
};

// 使用示例
const LargeList = () => {
  const data = Array.from({ length: 100000 }, (_, i) => ({
    id: i,
    title: `Item ${i}`,
    description: `Description for item ${i}`
  }));

  return (
    <VirtualList
      items={data}
      estimateHeight={60}
      renderItem={(item) => (
        <div className="list-item">
          <h3>{item.title}</h3>
          <p>{item.description}</p>
        </div>
      )}
    />
  );
};

2.3 请求性能:并发控制与缓存策略

前端经常需要处理并发请求和缓存问题。这里给出一个实用的请求缓存和并发控制方案:

// 请求缓存 + 并发控制
class RequestManager {
  private cache = new Map<string, { data: unknown; timestamp: number }>();
  private pending = new Map<string, Promise<unknown>>();
  private readonly cacheDuration: number;

  constructor(cacheDuration = 5 * 60 * 1000) { // 默认缓存5分钟
    this.cacheDuration = cacheDuration;
  }

  // 带缓存的请求
  async requestWithCache<T>(
    key: string,
    fetcher: () => Promise<T>,
    options?: { forceRefresh?: boolean }
  ): Promise<T> {
    // 1. 检查缓存
    if (!options?.forceRefresh) {
      const cached = this.cache.get(key);
      if (cached && Date.now() - cached.timestamp < this.cacheDuration) {
        return cached.data as T;
      }
    }

    // 2. 检查是否有相同的请求正在进行中(防止重复请求)
    if (this.pending.has(key)) {
      return this.pending.get(key) as Promise<T>;
    }

    // 3. 发起新请求
    const promise = fetcher()
      .then((data) => {
        this.cache.set(key, { data, timestamp: Date.now() });
        return data;
      })
      .finally(() => {
        this.pending.delete(key);
      });

    this.pending.set(key, promise);
    return promise;
  }

  // 手动清除缓存
  invalidate(key: string) {
    this.cache.delete(key);
  }

  // 批量清除缓存(支持正则)
  invalidateByPattern(pattern: RegExp) {
    for (const key of this.cache.keys()) {
      if (pattern.test(key)) {
        this.cache.delete(key);
      }
    }
  }
}

// 使用示例
const requestManager = new RequestManager(5 * 60 * 1000);

const getUserData = (userId: string) => {
  return requestManager.requestWithCache(
    `user:${userId}`,
    () => userApi.getDetail(userId)
  );
};

// 并发控制:限制同时请求数
class ConcurrencyLimiter {
  private queue: Array<() => void> = [];
  private activeCount = 0;
  private readonly maxConcurrent: number;

  constructor(maxConcurrent = 3) {
    this.maxConcurrent = maxConcurrent;
  }

  async run<T>(task: () => Promise<T>): Promise<T> {
    if (this.activeCount >= this.maxConcurrent) {
      // 等待有空闲位置
      await new Promise<void>((resolve) => {
        this.queue.push(resolve);
      });
    }

    this.activeCount++;
    try {
      return await task();
    } finally {
      this.activeCount--;
      // 唤醒队列中的下一个任务
      const next = this.queue.shift();
      if (next) {
        next();
      }
    }
  }
}

// 使用示例
const limiter = new ConcurrencyLimiter(3);

const batchFetchUsers = async (userIds: string[]) => {
  const results = await Promise.all(
    userIds.map((id) =>
      limiter.run(() => userApi.getDetail(id))
    )
  );
  return results;
};

三、复杂状态管理:超越Redux的思维

3.1 状态管理选型:不是所有状态都需要全局管理

很多团队把所有的状态都放进Redux/Zustand,这是错误的。正确的状态分层应该是:

// 状态分类与存储位置
type StateCategory = 
  | 'server'    // 服务端状态:需要异步获取的数据
  | 'url'       // URL状态:路由参数、查询参数
  | 'local'     // 组件本地状态:UI临时状态
  | 'global';   // 全局共享状态:用户信息、主题等

// 示例:正确的状态归属
const UserProfile = () => {
  // 1. URL状态 - 使用路由参数
  const { userId } = useParams();

  // 2. 服务端状态 - 使用React Query/SWR
  const { data: user, isLoading } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => userApi.getDetail(userId!)
  });

  // 3. 本地状态 - 使用useState
  const [isEditing, setIsEditing] = useState(false);
  const [formData, setFormData] = useState({
    name: '',
    email: ''
  });

  // 4. 全局状态 - 使用Context或状态管理库
  const { theme, toggleTheme } = useTheme();

  // ...组件逻辑
};

3.2 服务端状态管理:React Query实战

服务端状态和客户端状态是两种完全不同的状态,需要不同的管理策略。

// React Query 完整配置
import {
  QueryClient,
  QueryClientProvider,
  useQuery,
  useMutation,
  useQueryClient
} from '@tanstack/react-query';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5 * 60 * 1000,      // 5分钟内不重新请求
      gcTime: 30 * 60 * 1000,        // 30分钟后清除缓存
      retry: 3,                       // 失败重试3次
      retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000),
      refetchOnWindowFocus: false,    // 窗口聚焦时不自动刷新
      refetchOnReconnect: true        // 网络重连时刷新
    },
    mutations: {
      retry: 1,
      onError: (error) => {
        // 全局错误处理
        console.error('Mutation failed:', error);
      }
    }
  }
});

// 复杂查询:依赖查询 + 分页 + 乐观更新
const useUserWithPosts = (userId: string) => {
  const queryClient = useQueryClient();

  // 1. 基础查询
  const userQuery = useQuery({
    queryKey: ['user', userId],
    queryFn: () => userApi.getDetail(userId),
    enabled: !!userId // 依赖条件
  });

  // 2. 依赖查询:等user加载完成后再请求posts
  const postsQuery = useQuery({
    queryKey: ['user-posts', userId],
    queryFn: () => postApi.getByUser(userId),
    enabled: !!userQuery.data // 依赖userQuery
  });

  // 3. 乐观更新
  const updateUserMutation = useMutation({
    mutationFn: (data: Partial<User>) => userApi.update(userId, data),
    onMutate: async (newData) => {
      // 取消正在进行的查询
      await queryClient.cancelQueries({ queryKey: ['user', userId] });

      // 保存旧数据用于回滚
      const previousUser = queryClient.getQueryData(['user', userId]);

      // 乐观更新缓存
      queryClient.setQueryData(['user', userId], (old: User | undefined) => ({
        ...old!,
        ...newData
      }));

      // 返回上下文用于回滚
      return { previousUser };
    },
    onError: (error, _variables, context) => {
      // 出错时回滚
      if (context?.previousUser) {
        queryClient.setQueryData(['user', userId], context.previousUser);
      }
    },
    onSettled: () => {
      // 无论成功失败都重新获取最新数据
      queryClient.invalidateQueries({ queryKey: ['user', userId] });
    }
  });

  return {
    user: userQuery.data,
    posts: postsQuery.data,
    isLoading: userQuery.isLoading || postsQuery.isLoading,
    updateUser: updateUserMutation.mutate
  };
};

3.3 复杂状态机:XState处理复杂流程

当业务流程非常复杂(如支付流程、表单多步骤验证),使用状态机可以避免状态混乱。

// XState 状态机示例:支付流程
import { createMachine, assign } from 'xstate';
import { useMachine } from '@xstate/react';

interface PaymentContext {
  orderId: string | null;
  amount: number | null;
  error: string | null;
  retryCount: number;
}

type PaymentEvent =
  | { type: 'START'; orderId: string; amount: number }
  | { type: 'SUCCESS' }
  | { type: 'FAIL'; error: string }
  | { type: 'RETRY' }
  | { type: 'CANCEL' };

const paymentMachine = createMachine<PaymentContext, PaymentEvent>({
  id: 'payment',
  initial: 'idle',
  context: {
    orderId: null,
    amount: null,
    error: null,
    retryCount: 0
  },
  states: {
    idle: {
      on: {
        START: {
          target: 'processing',
          actions: assign({
            orderId: (_, event) => event.orderId,
            amount: (_, event) => event.amount
          })
        }
      }
    },
    processing: {
      invoke: {
        src: 'processPayment',
        onDone: { target: 'success' },
        onError: {
          target: 'failed',
          actions: assign({
            error: (_, event) => event.data.message
          })
        }
      }
    },
    failed: {
      on: {
        RETRY: {
          target: 'processing',
          actions: assign({
            retryCount: (context) => context.retryCount + 1
          }),
          cond: (context) => context.retryCount < 3 // 最多重试3次
        },
        CANCEL: { target: 'cancelled' }
      }
    },
    success: { type: 'final' },
    cancelled: { type: 'final' }
  }
});

// 在React组件中使用
const PaymentFlow = () => {
  const [state, send] = useMachine(paymentMachine, {
    services: {
      processPayment: async () => {
        // 调用支付API
        const response = await paymentApi.process();
        if (!response.success) {
          throw new Error(response.message);
        }
        return response;
      }
    }
  });

  const handleStart = (orderId: string, amount: number) => {
    send({ type: 'START', orderId, amount });
  };

  return (
    <div>
      {state.matches('idle') && (
        <button onClick={() => handleStart('order-123', 99.9)}>
          开始支付
        </button>
      )}

      {state.matches('processing') && (
        <div>支付处理中...</div>
      )}

      {state.matches('failed') && (
        <div>
          <p>支付失败:{state.context.error}</p>
          <button onClick={() => send({ type: 'RETRY' })}>重试</button>
          <button onClick={() => send({ type: 'CANCEL' })}>取消</button>
        </div>
      )}

      {state.matches('success') && (
        <div>支付成功!</div>
      )}

      {state.matches('cancelled') && (
        <div>支付已取消</div>
      )}
    </div>
  );
};

四、微前端架构:大型团队协作的解决方案

当多个团队共同开发一个大型应用时,微前端架构可以让每个团队独立开发、独立部署。

4.1 基于Module Federation的微前端

// 主应用配置 - webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'host',
      filename: 'remoteEntry.js',
      remotes: {
        // 加载子应用
        app1: 'app1@http://localhost:3001/remoteEntry.js',
        app2: 'app2@http://localhost:3002/remoteEntry.js'
      },
      exposes: {
        // 暴露给子应用使用的组件
        './Shell': './src/components/Shell',
        './Navigation': './src/components/Navigation'
      },
      shared: {
        // 共享依赖,避免重复加载
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
        'react-router-dom': { singleton: true }
      }
    })
  ]
};
// 子应用配置 - app1/webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'app1',
      filename: 'remoteEntry.js',
      exposes: {
        './UserManagement': './src/pages/UserManagement',
        './OrderManagement': './src/pages/OrderManagement'
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
      }
    })
  ]
};
// 主应用动态加载子应用组件
import React, { Suspense, lazy } from 'react';
import { Routes, Route } from 'react-router-dom';

// 动态加载远程组件
const UserManagement = lazy(() => import('app1/UserManagement'));
const OrderManagement = lazy(() => import('app2/OrderManagement'));

const App = () => {
  return (
    <div>
      <Suspense fallback={<LoadingSpinner />}>
        <Routes>
          <Route path="/users/*" element={<UserManagement />} />
          <Route path="/orders/*" element={<OrderManagement />} />
        </Routes>
      </Suspense>
    </div>
  );
};

4.2 微前端通信机制

// 微前端事件总线
class MicroFrontendEventBus {
  private listeners: Map<string, Set<Function>> = new Map();
  private static instance: MicroFrontendEventBus;

  static getInstance(): MicroFrontendEventBus {
    if (!this.instance) {
      this.instance = new MicroFrontendEventBus();
    }
    return this.instance;
  }

  // 订阅事件
  subscribe(event: string, callback: Function): () => void {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, new Set());
    }
    this.listeners.get(event)!.add(callback);

    // 返回取消订阅函数
    return () => {
      this.listeners.get(event)?.delete(callback);
    };
  }

  // 发布事件
  emit(event: string, data?: unknown) {
    this.listeners.get(event)?.forEach((callback) => {
      try {
        callback(data);
      } catch (error) {
        console.error(`Error in event listener for ${event}:`, error);
      }
    });
  }

  // 清除所有监听器
  clear() {
    this.listeners.clear();
  }
}

// 使用示例
const eventBus = MicroFrontendEventBus.getInstance();

// 子应用A:登录成功后通知其他应用
const handleLoginSuccess = (user: User) => {
  eventBus.emit('user:login', user);
};

// 子应用B:监听登录事件,更新用户信息
useEffect(() => {
  const unsubscribe = eventBus.subscribe('user:login', (user: User) => {
    // 更新当前应用的用户状态
    updateUserContext(user);
  });

  return () => unsubscribe();
}, []);

五、质量保障:类型安全与代码规范

5.1 TypeScript高级类型技巧

// 类型体操:构建更安全的类型系统

// 1. 条件类型:根据输入类型返回不同类型
type IsArray<T> = T extends any[] ? true : false;
type Check = IsArray<string[]>; // true
type Check2 = IsArray<string>;  // false

// 2. 映射类型:转换对象结构
interface User {
  id: string;
  name: string;
  email: string;
  password: string;
}

// 将可选属性变为必选
type Required<T> = {
  [P in keyof T]-?: T[P];
};

// 将属性变为只读
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

// 3. 工具类型组合
type PublicUser = Omit<User, 'password'>;  // 排除密码字段
type PartialUser = Partial<User>;          // 所有字段可选
type UserId = Pick<User, 'id'>;            // 只保留id字段

// 4. 模板字面量类型
type EventName = `on${Capitalize<string>}`;
// 约束事件处理函数名称
type ButtonProps = {
  [K in EventName]?: (event: Event) => void;
};

// 5. 递归类型:处理嵌套结构
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object
    ? DeepPartial<T[P]>
    : T[P];
};

interface NestedObject {
  a: {
    b: {
      c: string;
    };
  };
}

type PartialNested = DeepPartial<NestedObject>;
// 所有嵌套属性都变为可选

5.2 ESLint + Prettier 工程化配置

// .eslintrc.js - 团队统一规范
module.exports = {
  parser: '@typescript-eslint/parser',
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react-hooks/recommended',
    'plugin:import/recommended',
    'prettier' // 关闭与Prettier冲突的规则
  ],
  plugins: ['@typescript-eslint', 'react-hooks', 'import'],
  rules: {
    // React Hooks 规则
    'react-hooks/rules-of-hooks': 'error',
    'react-hooks/exhaustive-deps': 'warn',

    // TypeScript 规则
    '@typescript-eslint/no-explicit-any': 'error',
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/no-unused-vars': ['error', {
      argsIgnorePattern: '^_'
    }],

    // 导入规则
    'import/order': ['error', {
      groups: ['builtin', 'external', 'internal', 'parent', 'sibling'],
      'newlines-between': 'always'
    }],

    // 代码质量规则
    'no-console': ['warn', { allow: ['warn', 'error'] }],
    'no-debugger': 'error',
    'no-duplicate-imports': 'error'
  },
  settings: {
    'import/resolver': {
      typescript: {}
    }
  }
};
// .prettierrc - 统一代码风格
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 80,
  "bracketSpacing": true,
  "arrowParens": "always",
  "endOfLine": "lf"
}

总结

中级前端开发者的核心能力不在于会用多少框架,而在于:

  1. 架构能力:能设计出可维护、可扩展的项目结构
  2. 性能意识:理解渲染原理,能定位和解决性能瓶颈
  3. 状态管理思维:知道什么状态该放哪里,如何管理复杂状态
  4. 工程化能力:配置构建工具、规范代码质量、搭建CI/CD
  5. 协作能力:在大型团队中通过微前端等技术实现高效协作