1. 为什么我在 Cloudflare 上做“垂直”微前端,而不是“水平”的
先讲清楚一个容易混淆的点。大部分团队聊微前端,默认指的是“水平拆分”——也就是按业务域拆成多个独立应用,每个应用占一个完整页面,比如订单页是一个应用、商品页是另一个应用,通过路由层做分发。这种方案的好处是团队边界清晰,但坏处也很明显:页面之间的跳转是整页刷新级别的体验,公共数据要跨应用传递,Case 一多就成了“搬砖式”协作。
而我这里说的“垂直微前端”,指的是在同一个页面里,把不同的页面区块(区块)拆给不同团队独立开发、独立部署。比如一个 Dashboard 页面,上面是用户信息卡片,中间是订单趋势图,底部是消息列表,这三个区块分别由三个团队维护,但在浏览器里它们拼在同一个 URL、同一个页面里——这就是垂直拆分。
为什么我会想到在 Cloudflare 上做这件事?两个原因:
第一,Cloudflare 的 Workers 和 Pages 天然适合做轻量级的服务端聚合层,而且它们对边缘缓存和静态资源的处理非常成熟,可以用来做“区块级别的路由分发”。第二,垂直微前端的一半复杂度不在浏览器端,而在构建部署和版本协调——Cloudflare 的 CI 集成、Worker 路由、环境变量注入恰好能把这块成本压得很低。
所以这篇文章的主题是:把 Cloudflare 当作一个“组合平台”来构建垂直微前端,而不是仅仅把它当成 CDN 用。我会把整个架构的拆解思路、技术选型、落地方案和踩坑记录都讲清楚。
适合谁来参考:如果你所在的前端团队正在纠结要不要上微前端,或者已经在用传统方案但是被跨团队协作折磨得够呛,那这篇文章能帮你看到另一条路。不适合谁:如果你是单团队、单应用、产品逻辑也不复杂,垂直微前端是正儿八经的过度设计,别套方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 垂直微前端的核心设计思路
2.1 垂直拆分的三个关键维度
在做技术选型之前,先搞清楚垂直拆分到底拆什么。我在实践中发现,有三个维度必须同时考虑清楚,否则后面一定会打架。
第一是视觉维度。 垂直拆分天然对应着页面在纵向上被切成不同的区块。每个区块的高度、边距、背景色、是否懒加载,这些信息必须由“区块协议”来定义,不能由各个子应用自己拍脑袋。否则拼出来的页面会像补丁摞补丁。
第二是数据维度。 区块之间通常是有关联的,比如订单趋势图需要知道顶部的用户城市信息。垂直微前端的核心难点就在这里:数据不能写死在各区块内部,而是要有一个跨区块的状态通道。这块我后面会展开讲。
第三是生命周期维度。 每个区块不会同时出现、同时消失。有的区块需要等某个事件触发后才加载,有的只需要展示一次然后销毁。这个生命周期谁来管理?是容器应用统一管理,还是各区块管理自己?如果设计不好,就会遇到一种很常见的病:页面初始加载 3 秒,但 90% 的区块根本不需要首屏出现。
2.2 为什么 Cloudflare 适合做区块分发层
传统微前端架构里,一般有一个主应用(容器)负责加载子应用,比如 qiankun、single-spa 都是在浏览器端做这件事。这些方案本身没问题,但有一个隐藏前提:所有子应用的构建产物必须能被主应用从同一个域名下访问到,否则跨域、Cookie 等问题会让你疯掉。
Cloudflare 的 Workers + Pages 组合,恰好把这个“同一域名”的问题在边缘层解决了。具体来说:
- 每个子应用可以部署到独立的 Pages 项目,拥有自己独立的预览链接和生产链接;
- 在容器应用所在的 Worker 里,按照 URL 路径或请求头做分发,把不同区块的静态资源请求代理到对应的 Pages 项目上;
- 所有请求最终都走容器应用自己的域名,所以不存在跨域问题,也不存在 Cookie 失效问题。
这在传统方案里通常要靠 Nginx 或者网关层配置一堆路由规则,而在 Cloudflare 上只需要一两段 Worker 代码。而且由于 Worker 在各边缘节点就近执行,静态资源的响应速度不会因为多了一层分发而明显变慢,实测大多数区域首包耗时只增加了 5ms 左右。
3. 技术选型:容器、通信、样式隔离这三件套
3.1 容器层:用 Worker 承担“胶水”职责
垂直微前端的容器应用,我建议用 Cloudflare Worker 来实现“请求的组合”,而不是在浏览器端用 JS 手动拼接。这两种思路的差别很本质:
- 浏览器端拼接(类似 iframe 或动态 script)的问题在于:首屏性能吃亏,而且各子应用加载的时序很难控制;
- 边缘端拼接的做法是:Worker 把页面骨架的 HTML 直接返回给浏览器,浏览器拿到的是一个完整页面,而每个区块的内容是通过 Worker 在边缘端代理加载的。
具体实现不复杂。骨架 HTML 可以是静态文件,放在 Worker 的静态资源目录里。区块区域用 <div id="block-a"></div> 占位,Worker 收到请求后,根据当前用户身份和环境变量,决定哪些区块需要在服务端渲染(SSR),哪些只需要在客户端异步加载。
我最初也想过用 iframe 来承载垂直区块,因为 iframe 在样式隔离上是无脑方案。但后来放弃了,原因有三:iframe 之间的通信太别扭,滚动条和高度自适应永远是个坑,而且移动端性能开销大。所以最终还是走了 Worker 渲染 + 客户端动态挂载的混合路子。
3.2 通信机制:别再折腾 EventBus 了
垂直微前端的跨区块通信,是团队最容易翻车的地方。很多团队上来就搞一个 EventBus 或者全局事件中心,一开始确实爽,等到事件多了就变成了蜘蛛网——你根本不知道谁在监听谁。
我建议的通信方案是:用“状态容器 + 选择器订阅”的方式,而不是用事件广播。每个区块不是监听一个“订单更新”事件然后自己去拉数据,而是把自己的数据源交给一个共享的 Store(我用的类似于 Redux Toolkit 的轻量切片机制),区块只关心自己关心的切片。
在 Cloudflare 这个场景下,这个 Store 的数据可以来源于两个方面:
- 服务端通过请求头或 HTML 里注入的
window.__INITIAL_DATA__传递基础数据; - 客户端各区块通过 API 获取的数据,写入同一个 Store,供其他区块读取。
这样设计的好处是数据流可追踪,调试的时候能清楚看到每个区块读取了哪些字段。坏处是需要团队成员统一
