关于前端架构的思考

319 阅读6分钟

关于前端架构的思考

前端框架的发展

从前后端分离之后,前端开始了疯狂快速的发展,目前架构形式有 CSR,SSR,SSG 抑或 ESR...

每种架构都有其优势,那未来,前端的框架是怎样的?聚各家大成于一身?

这里,我们来先从用户侧对 WEB 应用的期望来慢慢探讨下。

用户希望一个 WEB 应用是怎么样的呢?(当然,这里可能也是科技的发展来带给用户未曾想象过的更好的体验) 至少从当下来看,个人认为 WEB 应用体验,也包括 Hybrid 体验,用户当前更希望是一个对比原生的体验;

更快的加载,更流畅的交互,更好的产品体验(当然这些不属于架构层面的我们就先不在这里讨论)

而从企业侧,也需要满足一定的商业目的,如 SEO;

从以上这些方面,我们再来简单罗列下上面提到的各种架构优缺点:

  • CSR: 优点:配合 SPA,一次加载完渲染完后,用户后续的交互体验比较好 缺点:首页渲染比较慢,需要等 js,框架代码加载完,框架运行时启动之后;再者就是比较差的 SEO。

  • SSR: 优点:更快的首屏加载,更快的 FCP 和 TTI,更好的 SEO; 缺点:更多的服务开发要求,服务器配置如负载均衡等;由于是后端渲染,并不能很好进行前后端职责分离,对于重客户端交互逻辑,表现并不优; 对比 CSR,它的 TTFB,FP 会滞后一些。

  • SSG: 静态页面生成,直接生成 HTML 页面,直接把静态页面资源存在 CDN 上; 优点:资源直接部署 CDN,合理利用缓存,获取最快的资源加载,及更快的首屏加载,更快的 FCP 和 TTI,更好的 SEO;(具有 SSR 的优点)同时也是客户端直接渲染; 缺点:只适用于静态数据,对于动态的数据,需要每次重新生成 HTML,抑或利用 hydration 等技术;

对比以上,单单只看一种单纯的架构,我们觉得差强人意。(虽然,框架也是依据具体业务而言,但对于大多数非特定的前端业务,都是一个复杂的;) 那一个很直接的想法就会冒出来。结合他们的优点不就行了? 答案是肯定的。

其实,个人认为,SSG 其实也是在 CSR 和 SSR 之间产生的一种方式;

我们再换个角度思路:

  • 前端能脱离客户端吗? 这么问,感觉很低级,怎么能脱离呢。那一点就直接明确了,我们定需要结合客户端的能力,及动态处理的能力;
  • 服务端渲染能提供什么? 服务端的能力,更在于更快的计算,按需提供给客户端直接需要的资源,减少客户端基于运行时再渲染的性能; (ps:目前我们所见,几乎所有的前端框架,都是有运行时的,这么思 考也是基于这些的) 基于服务端,对于动态的数据请求,也就有更短的路径,以及更前置的处理;

所以,更优的前端是:根生于客户端的,并能充分利用服务端的能力;

我们先单纯且简单的从上面的 CSR,SSR,SSG 看它们,是分离的。 架构是分离的,HTML 是整块页面的;

那怎么融合呢?简单来说,就是怎么利用上服务端(或 CDN)和客户端的能力;

既然服务端在处理交互上的能力有限,那服务端就注重静态 HTML 数据生成,因为静态的 HTML 数据的生成,初始情况下几乎都依赖数据请求。那现在服务端重点就在于此。客户端重点在于添加交互(事件等)。 (以上这些当拆分页面来看,是不是和 MPA 又类似;个人觉得,对于非静态站点,服务端提供的能力,如计算,更短请求路径等还是有更大作用的);

基于框架运行时,以及提供的 hydrate 的能力。来实现这样的融合。

具体我们从 React 的 hydrate 或者 hydrateRoot,以及 renderToPipeableStream 或 renderToNodeStream,renderToString 中发现。 (这里是脱水和水合的过程,服务端去除事件等,只发送 DOM 结构给客户端;客户端在参照该 DOM 结构的基础上,动态的补全其对应的事件,这就是一个客户端水合过程。充分利用之前的 DOM 结构,没有造成过多的渲染,但是运行时层面的大量计算还是有的。)

(ps:这里再谈一下运行时;运行时给了我们更多动态整合的能力,但也是家重了客户端的 js 执行压力。所有有一些框架尝试去最大限度的减小运行时如 Svelte & Solid 不使用如 React 中虚拟 DOM 层; 再如前端的框架设计,以 UMI 为例,利用运行时这一层,设计生命周期,整合处理框架配置和依赖等。)

收回话题。 使用 React 架构,或者使用 Next.js,我们很容易就发现这个。

以上,我们使用了水合。它能处理我们的问题,但还有可优化的余地,及怎么进一步提高水合的效率呢?及怎么能让用户更快速的进行交互。TTI 更短。

简单的思路,减小任务。这就先我们做按需加载一样。按需水合。 及 Islands Architecture--孤岛架构。

看 React 中的 Suspense,有没有感觉呢? 看下官方 Demo

// 该组件是动态加载的
const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    // 显示 <Spinner> 组件直至 OtherComponent 加载完成
    <React.Suspense fallback={<Spinner />}>
      <div>
        <OtherComponent />
      </div>
    </React.Suspense>
  );
}

这里背后也是利用‘孤岛架构’提供的能力;

进一步利用服务端的能力:

服务端组件,这也是 React 正热的话题。 优势:

  • 可直接访问服务端资源(如:数据库、文件系统、内部的微服务等)
  • 避免了不必要的客户端和服务端之间的交互,因此性能更快
  • 允许一些类库可以直接运行在服务端,因此减小了客户端包文件的大小;

了解更多

服务端组件,也是一种拆分逻辑或者说按需逻辑,对更细小的部分作为可执行单元来执行,达到更细颗粒的控制。是更高效的性能控制,从编程架构上,也是更符合单一责任原则;

服务端组件故名思议,及在服务端执行的组件,那必然也涉及与客户端的信息传递。当我们对于前端本身来考虑,结构优化之后,我们再考虑其他影响前端的因素有哪些?怎么基于这些来优化设计?

更多影响前端的因素?

其他影响前端的因素有哪些? 思考一个问题,当我们能在各种情况下,全面的思考时,我们的思考就更开拓了。

当我们再没有跟随上面的思路单独思考这样的一个问题时,我们可能很容易的回答。 这里我想说的是,http 协议。从文本传输到二进制的流式传输; 当我们再思考拆分部分的时候,考虑更底层的二进制层面的拆分。 --这里要看 React 的流式渲染,从 renderToNodeStream 到 renderToPipeableStream (github.com/reactwg/rea… ----TODO---

引用