前端与 BFF 进阶架构

深入前端架构演进:从单体前端到微前端、SSR/SSG/ISR 渲染策略、边缘渲染与 BFF 分层设计,理解现代化前端架构的完整技术栈。

前端与 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 耦合
QiankunJS 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 BFFNode.js / Go高并发、前后端可共享类型定义
GraphQL BFFApollo Server / graphql-go类型系统、按需获取
SSR 一体化Next.js / Nuxt.js前端框架原生支持
边缘 BFFCloudflare 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 达标 → 渐进增强 → 极致体验

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页