这本书在讲什么
《互联网产品的客户端架构》讨论一个具体问题:同一款产品,在用户手里的那台设备上,架构应该长成什么样。
它不教 TypeScript 语法,也不比较框架的 API。它从产品事实出发,讨论端上独有的约束怎样改变渲染、数据、状态与发布四条路径,并把这些判断写成可以运行、可以回归的代码。贯穿案例是「回声」——一个同时有内容流、私信与站内下单的产品;上一套《互联网产品的服务端架构》从服务器看它,这一套从端上看它。
四卷的分工是:
| 卷 | 主题 | 主要问题 |
|---|---|---|
| 卷一 | 端形态与体验基础 | 端上约束如何决定分层、状态、路由、数据与渲染 |
| 卷二 | 内容、社交与实时互动 | Feed、媒体、评论、IM、长连接、推送与离线同步 |
| 卷三 | 交易、增长与平台化 | 商品、购物车、支付、营销、实验、埋点与合规 |
| 卷四 | 多端、性能与架构演进 | 多端复用、微前端、性能体系、发布工程与组织协作 |
当前发布的是卷一。它先把地基打牢:如果状态归属、依赖方向、路由语义与数据层边界没定清楚,后面三卷讨论的复杂场景只会把问题放大。
卷一的结构
卷一 45 篇,由三部分组成:
- 前置 3 篇:序、前言、本目录。
- 正文 39 篇:13 章,每章 3 节。
- 附录 3 篇:指标与体验口径速查、端上问题排查手册、架构评审清单。
每一章对应实验工程里的一个目录,三个源文件对应三节,三个测试文件验证三节的核心断言。第 13 章把前面所有模块串成一条端到端流程,作为卷一的收口。
第 1 章 客户端架构的四个独有约束
先回答“客户端和服务端到底哪里不一样”。四个约束——设备碎片化、网络不确定、生命周期被打断、分发不可回滚——不是背景知识,而是后面所有决策的输入。
第 2 章 端形态谱系
Web、原生、小程序与桌面不是“同一个应用换层皮”。它们在能力、分发、更新与性能上的差异,会改变架构的默认值。本章给出可判定的能力矩阵与选型打分,而不是产品综述。
第 3 章 体验的质量属性
体验不是“感觉快”,而是一组可以被定义、采样与预算化的指标。本章讨论首屏、可交互、流畅度的口径,包体与内存预算,以及三者无法同时满足时的优先级。
第 4 章 分层与依赖
视图、状态、领域与数据访问四层各自负责什么、不负责什么。依赖必须指向内层,循环依赖要在构建前被发现。本章把分层写成可执行的架构测试,而不是一张墙上的图。
第 5 章 状态管理
状态归属是客户端的第一个决定。本章讨论本地状态与共享状态的边界、服务端状态的缓存与失效,以及什么时候该引入状态机、什么时候不该。
第 6 章 路由与页面栈
URL 是状态的一部分,但不是全部。本章讨论哪些状态该进 URL、页面栈的返回语义、深链进入后的恢复,以及失效链接的兜底。
第 7 章 数据层
端上的数据层要处理服务端不需要处理的问题:并发上限、超时预算、离线写入、冲突合并。本章把请求编排、缓存与同步队列写成可测试的模块。
第 8 章 组件体系
组件不是“可复用的 UI 片段”,而是带契约的单元。本章讨论设计系统与组件契约、受控与非受控的边界,以及可访问性为什么是架构问题而不是样式问题。
第 9 章 构建与产物
用户下载的是产物,不是源码。本章讨论打包与分包、按需加载、产物分析与体积预算,以及缓存与版本策略怎样影响发布。
第 10 章 渲染路径
CSR、SSR、SSG 与流式渲染不是“新技术清单”,而是四种不同的首屏权衡。本章讨论水合一致性、首屏与交互的错位,以及选择一种渲染模式后什么时候该退出。
第 11 章 错误与降级
端上的错误是常态,不是异常。本章讨论错误边界与白屏治理、弱网与接口失败的兜底,以及埋点补报与用户可恢复性。
第 12 章 端上观测
没有观测就没有架构判断。本章讨论性能指标口径、崩溃与卡顿归因、埋点规范与数据质量,重点在“口径”而不是“工具”。
第 13 章 卷一收口
把前十二章的模块串成回声客户端的基线:页面栈、状态、数据层、错误恢复与观测。本章给出模块依赖图、质量属性场景与风险清单,作为进入卷二前的检查点。
附录
三条阅读路径
顺序读:从第 1 章开始,按章推进。适合第一次接触客户端架构,或者想系统补齐判断依据的读者。每章结尾的小结会指向前后关联章节。
按问题读:如果你正在处理一个具体问题,可以直接跳到对应章节:
| 你遇到的问题 | 先读 |
|---|---|
| 页面白屏、崩溃后无法恢复 | 11.1、11.3、5.1 |
| 首屏慢、包体大 | 3.1、3.2、9.1、9.2 |
| 状态越写越乱、组件互相依赖 | 4.1、4.2、5.1 |
| 离线场景数据丢失或冲突 | 7.2、7.3、6.3 |
| 多端复用导致体验不一致 | 2.1、2.2、2.3 |
| 不知道选 CSR 还是 SSR | 10.1、10.2、10.3 |
按角色读:产品与设计读第 2、3、6 章,理解端上约束如何影响体验方案;客户端工程师按顺序读;技术负责人重点读第 1、4、13 章与附录 C,把判断变成团队可执行的规则。
章节之间的关系
卷一的章节不是并列的专题,而是一条有依赖的线。按顺序读时,前一章的输出会变成后一章的输入;跳读时,至少要知道自己跳过了哪一层。
- 第 1 章的四个约束,是第 2、3 章判断端形态与质量属性的输入。
- 第 2 章的端形态选择,决定第 9 章构建产物与第 10 章渲染路径的默认值。
- 第 3 章的质量预算,约束第 9 章的包体上限与第 12 章的观测口径。
- 第 4 章的分层与依赖方向,约束第 5 章状态归属与第 7 章数据层的位置。
- 第 5 章的状态归属,决定第 6 章哪些状态进 URL、第 7 章哪些状态落本地。
- 第 7 章的同步队列,依赖第 11 章的失败分类与第 12 章的补报机制。
- 第 8 章的组件契约,把第 4 章的分层规则落到视图层。
- 第 10 章的渲染选择,会反过来影响第 9 章的分包方式与第 3 章的首屏预算。
- 第 11、12 章是横切能力:任何一章的错误处理与观测缺口,最后都会在这里暴露。
- 第 13 章不再引入新概念,只把前面模块串成基线,并用风险清单检查遗漏。
这条依赖线也解释了为什么卷一不先讲性能优化。性能优化的前提是知道哪些路径是关键的、哪些状态不能丢、哪些模块可以独立加载;这些答案分别来自第 3、5、9 章。顺序颠倒,优化就会变成局部调参。
代码与实验工程
本书所有可运行代码放在实验工程 echo-client-lab 里,使用 TypeScript 与 Node 26 原生类型剥离,零第三方依赖。代码块开头的三行标记说明文件路径、可运行级别与验证命令:
// file: src/core/constraints.ts
// tier: L1
// verify: node --test test/core/constraints.test.ts
可运行性分三级:L1 验证纯逻辑,L2 验证进程内端到端流程,L3 验证本地服务与时序。真实浏览器渲染与真机性能不在承诺范围内,相关结论只给模型与检查方法。1.3 节详细说明这条边界。
数字、版本与边界
书中出现的用户量、比例、耗时与成本,除非明确标注为本机运行输出,都是案例假设值,用来演示判断过程,不是任何真实产品的实测。本机运行输出会附命令与原始文本,读者可以按同样的命令复现;耗时数字随机器变化,不作为性能结论。
版本口径:Node 26(本机验证 v26.5.0)、TypeScript 语法按 Node 原生类型剥离支持的范围。本书不绑定具体框架版本;涉及框架的部分只讨论判断方法。
本卷不讨论什么
边界写清楚,读者才不会带着错误的预期读下去。
- 不教语言与框架入门。TypeScript 语法见站内三部曲;React、Vue、小程序框架的 API 用法不在本书范围。
- 不做框架对比评测。书中提到框架时,只讨论它背后的架构假设,不比较性能分数或生态大小。
- 不承诺真机数据。启动耗时、帧率、内存占用需要真实设备与浏览器环境,本书只给口径、预算方法与排查路径。
- 不覆盖原生平台细节。iOS、Android、小程序的系统 API、审核规则与发布流程只讲到影响架构判断的部分。
- 不提供完整生产工程。
echo-client-lab是可验证的模型,不是可以直接上线的手架;工程化取舍需要结合团队与产品。 - 不讨论增长与商业策略。交易、营销与实验属于卷三;卷一聚焦端上基础能力。
章节与实验目录对照
每一章的代码放在实验工程的固定目录里,便于按章复现:
| 章 | 主题 | 实验目录 |
|---|---|---|
| 1 | 四个独有约束 | src/core/ |
| 2 | 端形态谱系 | src/forms/ |
| 3 | 体验质量属性 | src/quality/ |
| 4 | 分层与依赖 | src/layers/ |
| 5 | 状态管理 | src/state/ |
| 6 | 路由与页面栈 | src/router/ |
| 7 | 数据层 | src/data/ |
| 8 | 组件体系 | src/view/ |
| 9 | 构建与产物 | src/build/ |
| 10 | 渲染路径 | src/render/ |
| 11 | 错误与降级 | src/error/ |
| 12 | 端上观测 | src/obs/ |
| 13 | 卷一收口 | src/summary/ |
测试目录与源目录一一对应:test/core/、test/forms/,依此类推。每个测试文件只验证同名的源文件,跨模块流程放在第 13 章的端到端用例里。
读完卷一你应该能回答
- 给定一组产品事实,这份状态丢了会怎样,应该放在哪一层?
- 这个页面栈在冷启动、深链进入、进程回收后分别应该恢复到什么状态?
- 离线优先意味着哪些默认做法必须被禁止?
- 这个模块的依赖方向对不对,循环依赖该在哪里被拦住?
- 首屏、可交互、包体三者冲突时,优先级由什么决定?
- 这次发布需要兼容几个版本,旧客户端会看到什么?
如果这些问题还答不上来,回到对应章节;如果都能答上来,可以进入卷二,讨论内容、社交与实时互动在端上的具体形状。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。