29:47Vercel
Log in to leave a comment
No posts yet
一直以来,有一个困扰 Web 开发者的顽疾:仅仅因为调用了一个 cookies() 或访问了 Header,就会导致精心构建的整个静态页面被强制转为动态渲染。原有的 Next.js App Router 依赖于框架自动决定缓存的隐式模型。这种方式虽然看起来方便,但经常导致开发者在无意中破坏了整个组件树的缓存优势,陷入非全即无 (All-or-Nothing) 的困境。
Next.js 16 完全摆脱了这种二元思维。现在,你不再需要将整个页面定义为静态或动态。在一个页面内,精细化缓存的服务器组件——面包 (Bread),与需要实时交互的客户端组件——洞 (Hole) 可以共存,复合渲染 (Hybrid Rendering) 范式由此开启。理解这一变化不仅是出于技术好奇,更是降低服务器基础设施成本、最大限度提升 Lighthouse 分数的实战钥匙。
Next.js 16 最具颠覆性的变化是缓存变为了选择性加入 (Opt-in) 模式。将一切交给框架判断的时代已经过去,现在开发者需要使用 use cache 指令显式地在函数或组件级别声明缓存。
首先,需要在 next.config.ts 中开启实验性功能:
typescript // next.config.ts const nextConfig = { experimental: { dynamicIO: true, // 启用复合渲染及 use cache }, }
use cache 指令可以声明在文件顶部、组件内部,甚至是特定的异步函数内部。通过这种方式将部分预渲染 (PPR) 效率发挥到极致,可以将首字节时间 (TTFB) 缩短 60-80%。过去由于细微数据变化就必须重新渲染整个页面的情况,现在只需在特定的缓存边界内处理即可。
数据获取逻辑应当尽可能靠近使用该数据的组件,这被称为数据共存 (Data Colocation)。在顶层布局中获取所有数据并分发给子组件的方式,会增加组件间的耦合度,让维护变成噩梦。
Next.js 16 通过结合 React.cache 和 use Hook 解决了这一问题。得益于在同一渲染周期内防止重复请求的请求记忆化 (Request Memoization) 机制,即使多个组件调用同一个 API,网络请求也只会发生一次。
善用这一策略可以减少高达 70-80% 的客户端 JavaScript 量。由于服务器预先处理了数据并仅传递结果值,客户端无需承担沉重的逻辑负担。
甜甜圈模式是将静态部分 (Donut) 与动态部分 (Hole) 明确分离并进行组合的模型。
use cache 的服务器组件。负责处理数据获取和沉重逻辑,并对结果进行缓存。该模式的核心在于服务器组件通过 children 属性接收并渲染客户端组件的结构。即使父级服务器组件已被缓存,作为子级的客户端元素仍拥有独立的生命周期并正常运作。
useState 或 useEffect 的逻辑拆分为最小单位的客户端组件。use cache 并执行数据库查询。children 注入。Suspense 包裹动态的“洞”部分,确保静态外壳能立即渲染。如果应用了 use cache 后页面依然缓慢或呈动态运行,应怀疑是否存在 Dynamic API 泄露。如果在缓存边界内调用了 cookies() 或 headers(),该范围会立即转为动态渲染。应通过将这些值作为参数传递的方式来改进结构,而不是直接调用。
此外,所有异步数据访问必须位于 Suspense 内部。否则,框架会抛出访问未缓存数据的错误,并放弃静态生成。
Next.js 16 架构的性能提升数据非常明确:
| 性能指标 | 改进内容 | 预期效果 |
|---|---|---|
| TTFB (首字节时间) | 应用 PPR 及 use cache 时减少 60-80% |
大幅缩短服务器响应等待时间 |
| TBT (总阻塞时间) | 通过脚本 defer 策略减少主线程占用 | 改善用户输入响应性 |
| Build Time (构建时间) | 应用 Turbopack 后缩短 2-5 倍 | 提高开发效率及部署速度 |
如果在 Vercel 以外的环境(如 Docker)运行,务必使用 Redis 缓存适配器。通过它,数千个服务器实例可以共享一个中央缓存存储,从而最大限度减少数据库负载。
Next.js 16 不再强迫开发者在静态和动态之间二选一。现在的架构设计能力,取决于你如何精巧地将这两个世界交织在一起。
明智的开发者应当从识别那些因滥用 cookies() 而导致整体动态化的页面开始。接着,通过将数据获取逻辑移动到子组件来提高独立性,并利用 use cache 和甜甜圈模式最小化沉重库的影响。当你看到构建报告中页面显示为 Static 或 PPR 的那一刻,你便已经为可持续的高性能服务打下了坚实基础。