前端与 BFF 进阶架构 现代前端已从简单的页面展示演变为复杂的客户端应用。本文系统讲解前端架构的演进路径:从单体前端到微前端拆分、从 CSR 到 SSR/SSG/ISR 的渲染策略选择、边缘计算带来的渲染变革,以及 BFF(Backend for Frontend)分层设计模式。
1. 前端架构演进 1.1 单体前端 vs 微前端 单体前端(Monolithic Frontend):
┌──────────────────────────────────────┐
│ 前端应用(SPA) │
│ ┌────────┬────────┬────────┐ │
│ │ 商品模块 │ 订单模块 │ 用户模块 │ │
│ └────────┴────────┴────────┘ │
│ 共享状态、路由、组件库 │
└──────────────────────────────────────┘
问题:代码膨胀、构建慢、多团队协作冲突、技术栈锁定
微前端(Micro-Frontends):
┌──────────────────────────────────────┐
│ 基座/容器应用 │
│ ┌────────┬────────┬────────┐ │
│ │ 商品MF │ 订单MF │ 用户MF │ │
│ │(React) │(Vue) │(React) │ │
│ └────────┴────────┴────────┘ │
└──────────────────────────────────────┘
每个微前端可独立开发、部署、运行
1.2 微前端实现方案 方案 原理 优点 缺点 iframe 浏览器原生隔离 技术无关、隔离最强 SEO 差、体验割裂、通信复杂 Web Components 自定义元素 标准原生、框架无关 兼容性、样式隔离弱 Module Federation 运行时模块共享 共享依赖、无缝体验 构建复杂、Runtime 耦合 Qiankun JS Sandbox + 路由劫持 成熟方案、侵入性低 需适配、部分库不兼容 Single-SPA 注册 application 灵活、社区活跃 需自己处理样式隔离
1.3 Module Federation 示例 // 远程应用(Remote)webpack.config.js
const { ModuleFederationPlugin } = require ( 'webpack' ). container ;
module . exports = {
plugins : [
new ModuleFederationPlugin ({
name : 'productApp' ,
filename : 'remoteEntry.js' ,
exposes : {
'./ProductList' : './src/components/ProductList' ,
'./ProductDetail' : './src/components/ProductDetail' ,
},
shared : {
react : { singleton : true , requiredVersion : '^18.0.0' },
'react-dom' : { singleton : true },
},
}),
],
};
// 宿主应用(Host)
module . exports = {
plugins : [
new ModuleFederationPlugin ({
name : 'shellApp' ,
remotes : {
product : 'productApp@https://product.example.com/remoteEntry.js' ,
order : 'orderApp@https://order.example.com/remoteEntry.js' ,
},
shared : {
react : { singleton : true },
},
}),
],
};
// Host 中使用远程组件
const ProductList = React . lazy (() => import ( 'product/ProductList' ));
function App () {
return (
< div >
< h1 > 电商平台 < /h1>
< Suspense fallback = "Loading..." >
< ProductList />
< /Suspense>
< /div>
);
}
2. 渲染策略 2.1 CSR vs SSR vs SSG vs ISR 策略 渲染时机 首屏时间 SEO 服务端负载 适用场景 CSR 客户端 慢(需下载 JS) 差 极低 后台管理、强交互应用 SSR 每次请求服务端渲染 快 好 高 内容频繁变化、需 SEO SSG 构建时预渲染 最快(CDN 直达) 最好 无 博客、文档、营销页 ISR 构建时 + 增量更新 快 好 低 商品详情、新闻(折中方案)
CSR 流程:
浏览器 ──→ HTML 外壳 ──→ 下载 JS ──→ 执行 React/Vue ──→ 请求 API ──→ 渲染内容
(白屏等待)
SSR 流程:
浏览器 ──→ 请求页面 ──→ 服务端渲染完整 HTML ──→ 下载 JS ──→ Hydration
(可交互)
SSG 流程:
构建时 ──→ 生成静态 HTML ──→ CDN ──→ 浏览器直接拿到完整页面
ISR 流程:
构建时 ──→ 预渲染页面 ──→ CDN 缓存 ──→ 首次访问直接返回
──→ 后台异步重新生成(Stale-While-Revalidate)
2.2 Next.js ISR 实现 // Next.js ISR 示例
export async function getStaticProps ({ params }) {
const product = await fetchProduct ( params . id );
return {
props : { product },
revalidate : 60 , // 60 秒后后台重新生成
};
}
// 首次访问:返回缓存版本(可能旧)
// 60s 内再次访问:返回相同缓存版本
// 60s 后首次访问:返回旧版本 + 触发生成新版本
// 生成完成后:后续访问返回新版本
2.3 渲染策略选择决策 是否需 SEO?
├── 否 → CSR(后台系统、仪表盘)
└── 是 → 内容变化频率?
├── 几乎不变 → SSG(博客、文档)
├── 偶尔变化 → ISR(商品页、新闻)
└── 实时变化 → SSR(搜索页、社交动态)
3. 边缘渲染(Edge Rendering) 3.1 传统架构 vs 边缘架构 传统 SSR: 边缘渲染:
User ──→ CDN ──未命中──→ 源站服务器(Region 中心)
↑ ↑
静态文件 动态渲染
(延迟 50-200ms)
User ──→ Edge CDN(全球节点)
│
┌────┴────┐
↓ ↓
静态文件 边缘计算
(缓存) (V8 isolate 渲染)
↑
延迟 < 10ms
就近执行
3.2 Vercel Edge Functions // pages/api/hello.ts
export const config = {
runtime : 'edge' , // 在边缘节点执行
};
export default async function handler ( request : Request ) {
const { searchParams } = new URL ( request . url );
const name = searchParams . get ( 'name' ) || 'World' ;
// 在距离用户最近的边缘节点执行
return new Response ( JSON . stringify ({ message : `Hello ${ name } ` }), {
headers : { 'Content-Type' : 'application/json' },
});
}
3.3 边缘渲染优势 优势 说明 低延迟 代码在全球边缘节点执行,距离用户更近 高可用 边缘节点冗余,单点故障不影响整体 低成本 按需计费,无空闲资源浪费 个性化 基于用户地理位置/IP 返回定制内容 安全 DDoS 防护、Bot 检测前置
4. BFF(Backend for Frontend)分层设计 4.1 为什么需要 BFF 问题:多个前端渠道(Web、App、小程序、管理后台)
直接调用相同后端 API
Web 页面:
GET /user/123 → {完整用户数据 + 订单 + 配置} → 只需用户名和头像
过度获取 Over-fetching
App:
先 GET /user/123 → 再 GET /orders?user=123 → 再 GET /config
多次请求 Under-fetching
小程序:
API 数据结构不适合小程序组件结构,需大量转换
4.2 BFF 架构 ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Web │ │ App │ │ 小程序 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────────────────┼────────────────┘
│
┌────────────────┼────────────────┐
↓ ↓ ↓
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Web BFF │ │ App BFF │ │ MinaBFF │
│ - 页面级 │ │ - 屏幕级 │ │ - 页面级│
│ API │ │ API │ │ API │
│ - SSR │ │ - 数据聚合│ │ - 数据裁剪│
└───┬─────┘ └────┬────┘ └────┬────┘
│ │ │
└────────────────┼────────────────┘
│
┌─────────▼──────────┐
│ 领域服务层 │
│ ┌────┐┌────┐┌────┐ │
│ │用户││订单││库存│ │
│ └────┘└────┘└────┘ │
└────────────────────┘
4.3 BFF 职责 职责 说明 数据聚合 调用多个下游服务,组合成前端需要的结构 数据裁剪 只返回前端需要的字段 协议转换 GraphQL ↔ REST、gRPC ↔ REST 缓存策略 为前端定制缓存(TTL、失效策略) SSR 支撑 服务端渲染的数据源 边缘计算 在 CDN 边缘执行轻量逻辑
4.4 BFF 技术栈选择 场景 推荐技术 原因 通用 REST BFF Node.js / Go 高并发、前后端可共享类型定义 GraphQL BFF Apollo Server / graphql-go 类型系统、按需获取 SSR 一体化 Next.js / Nuxt.js 前端框架原生支持 边缘 BFF Cloudflare Workers / Vercel Edge 极致低延迟
5. 前端性能优化架构 5.1 资源加载策略 优化层次:
L1: 网络层
├── CDN 分发(静态资源全球加速)
├── HTTP/2 Server Push(关键资源预推送)
├── Brotli/Gzip 压缩(减少传输体积)
└── 资源预加载(Preload/Prefetch/Preconnect)
L2: 构建层
├── Tree Shaking(消除死代码)
├── Code Splitting(按需加载)
├── 资源内联(小资源直接嵌入 HTML)
└── 现代/传统包双模式(module/nomodule)
L3: 运行时层
├── 虚拟滚动(大数据列表)
├── 懒加载图片/组件
├── Service Worker 缓存
└── 骨架屏(提升感知性能)
5.2 Core Web Vitals 指标 指标 目标 测量内容 LCP < 2.5s 最大内容绘制(首屏主要元素加载) FID < 100ms 首次输入延迟(交互响应速度) CLS < 0.1 累积布局偏移(页面稳定性) TTFB < 600ms 首字节时间(服务端响应速度) FCP < 1.8s 首次内容绘制
6. 总结 现代化前端架构核心决策:
1. 应用拆分
单体 SPA → 微前端(团队规模 > 30 人考虑)
2. 渲染策略
CSR(后台) / SSR(实时内容) / SSG(静态内容) / ISR(折中)
3. 部署位置
源站渲染 → CDN 缓存 → 边缘计算( progressively closer to user )
4. 数据获取
直接调用后端 → BFF 聚合 → GraphQL 统一层
5. 性能目标
Core Web Vitals 达标 → 渐进增强 → 极致体验
继续阅读
探索更多技术文章 浏览归档,发现更多关于系统设计、工具链和工程实践的内容。