Islands Architecture
2022-08-02 · 1,751 chars · 9 min read
本文来自 Preact 作者 Jason Miller 的博客
我很难在网上找到这方面的参考资料,但今年在描述本文提到的这些方法时,听到这个名字被多次使用。据我所知,“Component Islands” 模式是由 Etsy 的前端架构师 Katie Sylor-Miller 在 2019 年的一次会议上提出的。
Islands Architecture 的总体思路非常简单:在服务端渲染 HTML 页面,并在高度动态的区域周围,注入占位符或插槽。这些占位符/槽包含了服务端渲染的 HTML 输出,来自其相应的小部件。它们表示的区域可以在客户端 “水合” 为小型的独立部件,重新使用其服务端渲染的初始 HTML。
译者注
Islands Architecture,大家应该都明白是什么意思,目前没看到什么好的翻译,个人感觉叫 “岛屿架构”、“群岛架构” 皆可。
类似几个名词还有 "Component Islands","Islands model"
你可以把它看作是一个静态的 HTML 文档,其中包含多个独立的嵌入式应用程序。
乍看之下,这似乎与 “微前端” 相似。这两种方法都有一个共同的思想,就是将应用程序分解成独立的单元,但是 “微前端” 不代表这些单元的组合是通过 HTML 实现的。
与 Islands 方法更接近的是 “渐进式增强”,我们本质上是通过添加 SSR hydration、一致性隐喻,来为页面的某个区域添加交互性。在传统的渐进式增强模式中,我们可能会有一个 <script>
标签,来寻找页面中的图片轮播,并在上面实例化一个 jQuery 插件。而现在,图片轮播会在服务器上被渲染,生成一个专门的 <script>
标签,来加载图片轮播的实现,并在原地将其升级为交互式的。
为什么这很重要#
事实证明,与典型的单页应用程序架构相比,此处描述的这组方法有很多好处。
零成本的渐进式水合#
我已经吹捧过 React、Angular、Preact 和 Vue 等框架的渐进式水合(Progressive Hydration)技术的性能优势了。通过这些架构,页面上的各个小部件会随着时间的推移被加载和初始化。这可以通过 requestIdleCallback
使用简单的调度方法来完成,也可以考虑其他因素,如视口的可见性、交互可能性、产品价值等。
与渐进式水合作用类似,使用 Islands Architecture 渲染页面,会让页面中较重的动态部分的初始化,不仅是渐进的,而且还是独立的。这意味着页面的各个区域,都能单独的变得可交互,而无需等待页面上其他内容的加载。
与渐进式水合作用不同,围绕 Islands Architecture 构建的页面不需要自上而下的渲染。这是一个明显的优势,因为没有必须在其后代之前就初始化的外部 root 组件。页面的每个部分都是一个独立的单元,一个单元中的性能问题不会影响其他单元。
SEO 和 UX 不是一种权衡#
单页应用的现状是,出于 SEO 的原因,常常认为 SSR 是必要的。然而,SSR 实际上会对用户体验产生负面影响——访问者盯着页面那令人沮丧的虚假版本,等待真正的功能初始化完毕。
很多应用并没有意识到自己陷入了 SSR 性能陷阱。在使用 Virtual DOM 的库中,很容易(并且很常见)意外地出现第一次客户端渲染,破坏了服务端渲染的 HTML 结构,导致渲染不一致,然后不得不从头开始重新创建它(通常是同步的)。
即使在 SSR 水合正常运行了,目前仍有很多不足之处。在页面加载期间执行的 JavaScript 代码量,相比 “有效” 代码量,仍然高出许多个数量级。
译者注
SSR 的页面会第一时间呈现给用户,但是只有当 js 加载完毕,执行完毕后,功能才是真正可用的:
- 功能方面:用户看到了但是不能操作
- 性能方面:大量 js 在页面加载完成后集中的解析、执行,FID 必然受到影响
这就是 Progressive Hydration 和 Islands Architecture 要解决的问题。但实际上,某些场景下 SSG + CSR 才是更好的 选择。
在 Island 模型中,服务端渲染不是为了改善 SEO、也不是为了 UX 的优化。相反,它是页面发送到浏览器的基本部分。响应给浏览器的 HTML 包含用户请求的,有意义且可以立即渲染并呈现的内容。
HTML 的某些部分可能会缺失其客户端的交互性,但它至少应包含最基本的内容。例如:一个新闻页面的 HTML 将包含文章正文,而一个产品页面将包含该产品的描述。
其他次要内容,是否纳入到 HTML 中,应该是一个产品层面的决策。它对访问该页面的用户来说有多重要?这个小部件对商业模式有多重要?一个与收入直接相关的 “立即购买” 按钮应该被优先考虑,而不是一个与信息收集相关的 “反馈” 按钮。
更好的可访问性和可发现性#
使用标准 HTML 链接进行导航的网站,更易于 “辅助技术” 和 “网络爬虫” 使用。无论链接或表单是否被 JavaScript 拦截并重新路由,这都是正确的,因为基本假设仍然正确:单击链接导航到指定页面。
就事论事,回想一下,有多少次别人发给你一个 “链接”,他们认为是他们正在浏览的页面,但是你打开后却完全不是那么回事儿,你还需要点几个按钮、切换几个 tab...
构建基于页面的应用程序并不能完全阻止这些类型的奇怪体验,它只会让决定变得更加直接。它使默认的结果成为可访问的结果。
结语#
归根结底,选择一个需要更少代码的架构是具有长期收益的,未来的你自己(或同事)都会感谢你的。有可能(甚至可能)采用这样的架构需要更多的前期设计思考。在将应用程序分解为可独立交付的小部件方面,现成可选择的框架很少,谁知道呢,也许我们可以解决这个问题。