译:用 Bun 实现 PPR

原文:https://aralroca.com/blog/partial-prerendering
作者:aralroca
译者:ChatGPT 4 Turbo

编者注:一句话理解 PPR,就是把 AOT 应用在渲染上。

在现代 Web 开发中,优化 Web 应用程序的性能至关重要。一种逐渐流行的方法是部分预渲染(partial prerendering),这是一种结合了静态和动态内容渲染的技术,能够增强打包大小和运行速度。在本文中,我们将深入了解部分预渲染的概念,并探讨其好处,尤其是通过提前渲染(AOT)实现时的优势。

此外,我们还将看到如何使用 Bun 插件来轻松地在每个 JSX 框架中应用它。

部分预渲染的工作原理

在使用 JSX 组件工作时,我们通常生成静态和/或动态页面。一些框架允许你在编译期间预渲染静态页面,这显著提升了初始加载时间。然而,大多数路由既不是完全静态的,也不是完全动态的。你可能有一个既含静态又含动态内容的路由。

部分预渲染(PPR)涉及在构建时渲染静态组件,并将动态组件的渲染推迟到运行时。这意味着,与其动态渲染所有组件,不如在构建过程中将某些组件预渲染为 HTML。

考虑到服务器端渲染(SSR),在许多情况下,我们会有完全静态的组件,例如头部、尾部等,如果我们在构建时只预渲染一次,然后无需为每个请求重复渲染,我们可以节省这些组件的渲染毫秒数。

蓝色部分是运行时渲染时间:

render vs partial prerender

还有一些情况,即便是组件中消费的数据也可以是静态的,想象一下,我们想在电子商务首页显示静态数据部分,在其中你必须硬编码一个 JSON 文件以加快速度,但是:

  • 需要解析 JSON 并渲染组件。
  • 我们在数据库和硬编码数据之间有重复的数据。

在这种情况下,我们可以直接从源头请求它们,而不是将它们硬编码,并提前渲染组件,以节省解析和渲染的毫秒数。

优势

  • 更小的打包大小
  • 更快的运行时渲染
  • 在每个请求上花费较少的资源
  • 更好的用户体验
  • 更好的搜索引擎优化

Bun 引入了 的概念到 JavaScript 中。宏是一种新的范式,仅通过添加一个 导入属性 就可以提前进行优化。

import { random } from './random.ts' with { type: 'macro' };

console.log(`你的随机数是 ${random()}`);

通过添加这个导入属性 macro,宏在打包时运行这个 random 函数。这些函数返回的值直接内联到你的打包文件中。

这样,像静态数据这样的事物可以直接从源头请求,而不是硬编码它,并提前完成工作。打包器在运行宏之后执行死代码消除,然后我们将有一个更小的打包大小。但是,我们可以用宏直接预渲染组件吗?

嗯,对于 Bun 转译器和宏之间的通信,数据必须被序列化,所以不是所有的数据都支持,只支持以下数据:

据我们所知,函数作为一种数据结构不被支持,而组件是函数!那么,我们可以从宏预渲染一个组件吗?

答案是可以的,但不是通过 Bun 的宏以一种优雅的方式。你必须传递组件所在的绝对路径字符串,并从宏中导入它,渲染它,并传递带有 html 字符串注入的结果 JSX。

本文的目的不是详细解释如何通过 Bun 宏完成预渲染,因为这会让开发者每次想要预渲染组件时都觉得太麻烦。但请继续阅读,因为现在感谢 Bun 插件,你可以用一种简单的方法集成它。

预渲染宏

去年夏天,我开始了 Brisa,一个实验性框架,我希望今年夏天能够对外公开。我长期以来一直有的一个特性是能够创建静态与动态之间的混合页面,并且使用起来非常简单。当我发现了 Bun 宏的想法时,我首先想到的是必须有类似的东西存在,用来预渲染组件,现在我已经公开了这个 Bun 插件,所有 JSX 框架都可以利用这项功能。

今天我发布了 Prerender Macro Bun 插件。从今天开始,部分水合可以通过以下方式用 Bun 来管理:

import StaticComponent from "@/static-component" with { type: "prerender" };
import DynamicComponent from "@/dynamic-component";

return (
  <>
    <StaticComponent foo="bar" />
    <DynamicComponent />
  </>
);

我邀请你尝试 演示

使用 React 和 prerender-macro 的示例

下一步

PPR(部分预渲染)的概念并不是什么新鲜事,最近 Vercel 与 React 和 Next.js 的人一起使基于 Suspense 组件的 PPR 成为可能,并且能够在最近的边缘节点上提供静态部分。这是个绝妙的主意。

通过 Prerender Macro,我为开源社区贡献了自己的一份力量,使其可以结合使用或者在不同的上下文中以不同的方式使用,因为对于 0.1 版本,它是将 HTML 注入到 JSX 树本身,而不是从边缘节点获取。然而,我希望未来的版本能生成基础设施即代码(IaC),以连接到必要的云服务(Vercel 或其他实现 PPR 的服务)。现在这个库已经开源,任何此方面的贡献都将受到非常欢迎。

Demos

这里有 BrisaReactPreact 的演示。但随时可以 添加 更多 JSX 框架,以帮助人们了解他们需要适应框架的插件配置。

照片由 Clay Banks 在 Unsplash 上摄影

想进一步了解 Brisa 框架等信息,请立即订阅我的博客通讯!

参考资料