前端 SSR 的落地实践

null


全文 3268 字,预计阅读时间 8 分钟

目录:

一、名词解释

二、业务背景:新增服务市场业务线

三、困境:服务端的渲染由后端主导,前端只负责产出静态(浏览器端执行)js 文件

四、重新开始:前端也能做服务端渲染,js 也能在服务端生成 html

  • 1:引入 Node.js 做服务渲染层
  • 2:确定 SSR 技术方案 node-vue-ssr

五、新的挑战:Node.js 和 SSR 的加入,同构逻辑冗杂

六、合理分层:拆解不同端的复杂度,一次开发多端生效,提高开发效率

七、配置化开发:每一层开发单元如何工作传递给下一层

  • 1:node 层:数据抓取和 SSR 渲染
  • 2:前端工程化:客户端和服务端的桥梁
  • 3:数据配置层,维护数据一致
  • 4:状态处理层:对于获取的数据进行筛选
  • 5:页面层:渲染

八、其他:

九、结语:

  • 优势
  • 缺点
  • 对比:在 rd 机器静态产出和改造后在 Node 机器上经过 SSR 构建的各项指标对比
  • 1:加载总时长时长
  • 2:其他指标对比
  • 未来和展望


一、名词解释:

null


二、业务背景:新增服务市场业务线

随着百度爱采购的发展,我们致力于打造自己的商业生态,以爱采购为核心,以搜索流量为基础,打造服务市场平台。服务市场致力于服务全网 B 端商家。搜索流量是我们的基石,我们需要服务端渲染来提高我们的搜索排名,当然服务端渲染也能提高一部分用户体验。

三、困境:服务端的渲染由后端主导,前端只负责产出静态(浏览器端执行)js 文件

我们是爱采购前端团队,爱采购的整体技术设计是后端采用 php 服务,C 端以 Smarty 渲染引擎来进行渲染。前端通过工程化,产出 Smarty 引擎源文件。导致前后端并未彻底进行前后端分离,前端过于依赖后端渲染,整体的优化和提效过于局限。新的系统期望继承老系统的优势,丢掉它的包袱,在不足之处重新开始。


流程图如下:

null


四、重新开始:前端也能做服务端渲染,js 也能在服务端生成 html

经过调研分析,Node.js 也能支持服务端渲染,而且性能并不逊色于 php 的 Smarty 渲染引擎,在整个部门围绕着提效和跨平台协作的前提下,整个服务市场的技术选用 Node.js 作为渲染引擎,以增强前端能力实现跨平台和提效。


流程图如下:

null


1:引入 Node.js 做服务渲染层


本身,渲染就是前端的工作量,引入 Node.js 层来做渲染,主要是减少后端关注点,使后端仅作为数据层,让后端更加专注,前端可以介入服务端,连接服务端和客户端,增强工程化能力。


2:确定 SSR 技术方案 node-vue-ssr


得益于技术的进步,现有的 Node.js 服务端渲染有有很多的技术可选择性:nuxt、node-vue-ssr


通过团队已实践的 node-vue-ssr 和已有的 vue 技术栈,最终选用了 node-vue-ssr。


node-vue-ssr 的实现流程:具体请参考文档 https://ssr.vuejs.org/zh/


null


五、新的挑战:Node.js 和 SSR 的加入,同构逻辑冗杂

1、状态中需要加入 SSR 和 CSR 的状态判断


2、在数据统一处理上,Nuxt.js(vue-ssr 的一个框架)会通过 asyncData(一个服务端和客户端都会在每个页面渲染前运行的配置函数)来保持 nodejs 和客户端的数据一致,这种方式有很大的弊端


效率低:每开发一个页面,都要进行书写请求逻辑(串行数据和并行数据)、网络异常处理逻辑(网络请求失败、后端异常状态码、未登录去请求登录的数据)


扩展性差:对于后续扩展跨平台活动页实现难度大(效率太低、代码耦合在一个函数里面,很难进行 lowcode 的升级)


为了解决这些问题,对问题进行了拆解,并将数据的获取处理,分层(客户端和服务端代码分离)多步执行,以达到高扩展性,高效开发,维护简单,快速锁定问题等优点

六、合理分层:拆解不同端的复杂度,一次开发多端生效,提高开发效率

null


七、配置化开发:每一层开发单元如何工作传递给下一层

1:node 层:数据抓取和 SSR 渲染


node 层获取用户访问的路由、根据路由信息前置获取数据配置层的数据,同时获取公共数据(用户信息)交给状态处理层。


2:前端工程化:客户端和服务端的桥梁


通过工程化解决一套代码开发,多端运行。代码可以在服务器运行生成 html 节点,代码在浏览器运行 js 进行交互生成 html。


3:数据配置层,维护数据一致


根据数据配置层的配置信息,会从 Node.js 端和客户端获取同一份数据,这样可以保障在访问同一个路由,不管是客户端构建还是服务端构建,数据是相同的,构建渲染结果也是一样的。


配置信息:




export default {// 标题"title": "服务市场","name": "home",// 路由匹配"path": "/",// 是否需要 ssr 构建"ssr": true,// 请求参数"ajax": [// 并行接口 {"path": "/home/info",// 串行接口"children": [{"path": "/home/getProductConf","params": {// 依赖父接口的参数"name": 'parent.data[0].data.name' } }] },// 并行接口 {"path": "/home/getProductConf" } ]}


null


由工程层的配置,我们强化配置文件,使项目的所有页面支持三种灵活配置:


1、对于客户端体验要求比较高的,并且有 seo 需求的,采用 SSR 构建


2、对于用户体验要求相对一般的、采用数据端预取方式


3、对于静态页面采用客户端 js 展示即可


4:状态处理层:对于获取的数据进行筛选


一个项目的页面有很多状态,例如用户中心需要登录,如果未登录,要显示未登录界面。如果数据获取失败,要显示获取失败界面。


这样的状态,在以往项目中有很多的冗余代码。


状态处理层根据页面的配置进行处理数据,状态处理层交付给页面层的,只有成功的数据。同时如果不成功(未登录、获取数据失败等)展示对应的状态。


null


5:页面层:渲染


得益于合理的分层和逻辑的拆解,整个页面层仅用于交互和页面数据渲染。

八、其他:

灵活配置:同时支持服务端渲染、数据直出渲染、以及客户端 CSR 渲染三种渲染方式。


灾备方案:在服务端渲染出现 bug 的情况下,可灵活转换为客户端渲染。


日志采集:对每个请求进行采集,记录当前的 cup、内存能性能参数,在发生问题后及时报警


问题锁定:对于每个请求每个渲染,从后端到前端生成唯一的 logid,对发生问题的请求进行快速的问题锁定


九、结语:

优势:

前端进行 SSR 渲染赋予了我们项目活力、更加灵活的配置,更好的用户体验,更强大的功能,更好的迭代,更高的安全性和容错率。


缺点:

Node.js 层的引入,造成成本增加


对比:在 rd 机器静态产出和改造后在 Node 机器上经过 SSR 构建的各项指标对比


(1)加载总时长时长


null


图 1:渐进式 CSR 加载总时长 1.7s

图 2:SSR 加载总时长 1.2s 提升 30%


(2)其他指标对比


null


null


图 1:渐进式 CSR 渲染首次绘制 243ms 后,首次内容绘制 943ms,结束绘制 1243ms


图 2:SSR 渲染 首次容绘制和内容绘制 427ms,结束绘制 1027ms


FP (First Paint) 首次绘制

FCP (First Contentful Paint) 首次内容绘制

LCP (Largest Contentful Paint)最大内容渲染

DCL (DomContentloaded): 解析完毕


未来和展望:


通过性能对比,整体收益远不止眼前的这些,未来我们期望大致以爱采购为核心的买卖生态,继续推行配置化落地,以数据来描述各个页面,以 Node.js 为基础渲染服务驱动各个页面以实现前端微服务和跨平台的活动页定制。


如果文章对你有帮助,别忘记评论、点赞、Get!

文章为作者独立观点,不代表BOSS直聘立场。未经账号授权,禁止随意转载。