前端架构到底是什么(以及它不是什么)
前端架构是代码库中边界的有意结构。它不是你通过 npm 安装的框架的名称。
目录
现代 web 开发中最常见的错误诊断听起来像这样: “我们的前端架构是 React 加 Tailwind。”
React 是一个 UI 库。Tailwind 是一个样式系统。它们都不是架构。
如果你相信你的框架就是你的架构,你就会停止做出结构性的决策。你将让框架默认的文件路由器来支配你的数据流。你将让你的组件在同一个文件中获取它们自己的数据,管理它们自己的领域逻辑,并处理它们自己的样式。那不是架构。那是等待骨化的、未被驯服的偶然复杂性泥潭。
前端架构 是边界的有意识设计。
架构作为边界系统
良好的架构使团队能够改变系统的一部分而不会破坏其他一切。它通过强制执行边界来做到这一点。
组件边界(关注点分离)
经典的关注点分离意味着将 HTML、CSS 和 JavaScript 拆分到不同的文件中。现代的组件驱动开发改变了这一点:我们现在按功能而不是文件类型来组织代码。
然而,这种关注点仍然存在。一个 UI 组件不应该同时组装 API URL、将原始 JSON 解析为领域对象、执行业务规则,并渲染标记。
graph TD
subgraph 泥潭(偶然架构)
B1[按钮组件] -->|获取数据| B2(原始网络响应)
B1 -->|解析| B3(领域逻辑)
B1 -->|渲染| B4(UI)
end
subgraph 边界(有纪律的架构)
D1[数据层] -->|标准化| D2[领域层]
D2 -->|传递 Props| P1[表现层]
end
偶然架构的例子: 一个 UserProfile React 组件调用 fetch(),手动检查 user.age > 18,如果检查失败则返回一个红色的徽章。如果年龄规则更改为 21,你必须找出每一个手动检查年龄的 UI 组件。
边界纪律的例子: 一个专用的 User 领域模块导出一个 canDrinkAlcohol(user) 函数。 UserProfile 组件导入该函数。UI 知道如何渲染红色徽章;领域模块知道规则。
状态边界
状态应该被限制在尽可能窄的边界内。
- 本地状态: 短暂的 UI 关注点。这个下拉菜单打开了吗?这个输入框里输入了什么?(属于组件内部)。
- 功能状态: 在特定功能领域内共享的状态。(属于上下文提供者或功能范围的 store)。
- 全局状态: 整个应用程序都需要知道的状态,比如当前登录的用户或选择的主题。(属于全局 store)。
失败模式: 将像 isDropdownOpen 这样的布尔值放入全局的 Redux store 中。这将一个微观的 UI 细节耦合到了全局架构中,迫使不必要的重新渲染。
渲染边界
并非所有像素都是平等的。架构要求决定代码在何处以及何时变成 HTML。
如果你以相同的方式对待营销网站和复杂的 SaaS 仪表板,那么你的架构就失败了。营销网站需要静态的渲染策略来实现 SEO 和速度。SaaS 仪表板需要客户端的交互性。选择错误的渲染边界会带来永久的性能惩罚。
四种架构模式
不同的产品形态需要完全不同的边界系统。
1. 内容出版物(例如,Interface Atlas)
- 主要边界: 内容模型(信息架构)。
- 状态: 极少甚至没有。
- 渲染: 带有选择性交互群岛的静态 HTML。
- 架构重点: 确保内容与布局组件解耦,以便对其进行查询和重用。
2. 单页应用程序 (SPA)
- 主要边界: 客户端状态和路由。
- 状态: 复杂的、高度标准化的客户端缓存。
- 渲染: CSR 或全页 SSR/水合。
- 架构重点: 管理服务器数据库和客户端内存之间的同步。
3. 设计系统 (Design System)
- 主要边界: UI 组件的 API 契约。
- 状态: 严格控制的本地 UI 状态;完全不关心领域数据。
- 渲染: 必须支持多种环境(React、Vue、Web Components)。
- 架构重点: 一致性、可访问性,并防止对使用方团队造成破坏性更改。
最终启发式
对前端架构的考验不是它是否使用了最新的框架。考验是当需求发生变化时会发生什么。
如果改变后端的据结构需要重写你的 UI 组件,那么你的边界就失败了。架构是一门保护 UI 不受数据库影响,并保护数据库不受 UI 影响的学科。
相关指南和术语
深入探索,请参阅:
- 信息架构与内容架构 — 知识结构如何驱动 UI。
- 作为架构的 Web 性能 — 渲染决策如何影响性能。
- 选择合适的技术栈 — 如何将产品形态映射到技术栈。