前端进阶实战:工程化架构、性能优化与复杂状态管理
引言
当你已经熟练掌握了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"
}
总结
中级前端开发者的核心能力不在于会用多少框架,而在于:
- 架构能力:能设计出可维护、可扩展的项目结构
- 性能意识:理解渲染原理,能定位和解决性能瓶颈
- 状态管理思维:知道什么状态该放哪里,如何管理复杂状态
- 工程化能力:配置构建工具、规范代码质量、搭建CI/CD
- 协作能力:在大型团队中通过微前端等技术实现高效协作