1.3 同构应用
同构应用或通用应用是指代码在服务器端和客户端之间共享并且在两者中都可以运行的 Web 应用。这种技术在可交互时间、A/B 测试和 SEO 这些方面尤其有效。由于可以在服务器端生成页面,我们可以专注于项目的关键特性来优化代码。
Web 应用在服务器端和客户端之间共享代码,因此,可以由服务器端来渲染浏览器请求的页面。服务器端从数据库或微服务取回需要展示的数据并进行处理,然后通过使用模板系统进行预渲染来生成视图。这样一来,提供给客户端的页面不需要往返请求数据就能显示。
因为页面已在后端预渲染,并且完成了部分或全部解析,所以页面的可交互时间会被提前。这避免了前端的大量请求,也就是说,前端不需要加载额外的资源(比如 vendors 包、应用代码),浏览器可以直接解析这个几乎已经包含了所有资源的静态页面。
同构应用还有利于 SEO,因为页面是在服务器端渲染的,不需要另外请求服务器端。既然同构应用不需要往返请求服务器端就能提供包含所有信息的 HTML 页面,爬虫就可以立即为它创建索引。
虽然同构应用在服务器端和客户端之间共享代码,但是实际上共享多少代码取决于对服务器端和客户端的设计。例如,我们可以混合使用不同技术,在服务器端渲染页面的一部分以使可交互时间提前,然后懒加载其他的 JavaScript 文件,这样做结合了同构应用和单页应用的优势。在 HTML 页面中加载的文件会为页面添加复杂的行为逻辑,从而把页面转变为单页应用。
通过这种方式,我们可以根据项目的需求来决定共享多少代码。比如,为了有一个可以让浏览器快速加载的 HTML 骨架,服务器端渲染视图时可以只内联 CSS 和尽可能少的 JavaScript 代码。再比如,假设客户端的页面没有太多的复杂交互,就可以把所有的渲染逻辑和数据处理都放在服务器端。我们也可以采用混合的方式,把应用分为多个单页应用,第一个视图在服务器端渲染,然后在客户端再另外下载一些 JavaScript 文件来管理单页应用内的行为、模型和路由。
路由是同构应用的另一个有趣的部分。我们可以在服务器端管理路由,当用户在客户端点击链接时,就提供一个静态页面。
我们也可以采用混合的方式,只对第一个视图使用服务器端渲染,接着加载单页应用,而服务器会做一个全局路由,服务于多个单页应用。每个单页应用都有自己的路由系统,以便在视图之间导航。如果采用这种方式,我们就可以不受模板库的限制,使用 React、Preact 等虚拟 DOM(document object model)来实现。许多其他的库和框架已经开始提供开箱即用的服务器端渲染,比如 Vue(结合 Nuxt.js)、Meteor 和 Angular。
关于同构应用最后要提到的是,我们可以不费吹灰之力就很好地集成 A/B 测试平台。A/B 测试是用一个页面的两个或多个版本同时进行实验,看哪个版本的效果最好。在过去一年左右的时间里,许多 A/B 测试平台不得不追赶前端技术,不仅要支持 jQuery 等 UI 库,还要支持 React 和 Vue 等虚拟 DOM 库。此外,它们还要支持 Hybrid 应用和原生应用。
这些公司采取的策略是在服务器端管理实验,以利用代码在服务器端和客户端都能运行的同构特性。如果你正在使用同构应用,这显然是一个很大的优势,因为你可以在服务器上预渲染你要为特定用户设计的实验。为了选择合适的实验,这些解决方案还可以通过 API 与客户端的原生移动应用和单页应用进行通信。
但是,如果一个采用同构应用的项目相当成功,有数百万用户访问,那么可能会面临可扩展性问题。因为生成的 HTML 页面是在服务器上预渲染的,所以需要创建合适的缓存策略以降低对服务器的影响。在这种情况下,如果对用户请求的缓存做得好,像 Akamai、Fastly 和 Amazon CloudFront 这样的 CDN 无疑会提高同构应用的可扩展性,因为它们避免了所有请求都发送到源服务器。从组织上看,同构应用和单页应用存在类似的问题,它们都仅有一个代码库,并且可能由多个团队维护。
如果每个团队都明确只负责应用的某个部分,而且不和其他团队有任何重叠,那么就有一些方法可以降低团队间的沟通成本。在这种情况下,我们可以使用像 BFF(backends for frontends)这样的架构来解耦 API 的实现,并且让每个团队都只维护自己关注的 API 分层。