0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

天猫汽车商详页的SSR改造实践

OSC开源社区 来源:OSC开源社区 2023-02-03 14:54 次阅读

由于汽车业务的特殊性,天猫汽车基于 Rax 多页应用自建了商品详情的 H5 页面。自定义商详承载了众多业务能力和投放场景。随着业务的发展和页面承载内容的增多,开始出现白屏时间太长等体验问题。

前端性能优化算是个老生常谈的问题,我们的页面已经做过首屏接口合并、图片懒加载、骨架屏等体验优化,想进一步提升用户体验就要从渲染机制和渲染容器入手了。从容器侧看,淘宝端原生提供的 pha 容器提供的数据预请求、资源离线缓存等功能,可以有效提升手淘内的 H5 页面体验。但是其它渠道的端缺少类似容器能力,需要从渲染机制方向寻找出路。

SSR(Server Side Render)是相对于现有渲染机制CSR(Client Side Render)的一种渲染方案。在用户通过客户端(Client Side)请求页面资源时,CSR 拿到是一份空文档,再通过数据请求、执行渲染脚本后生成文档,最后展示给用户。而 SSR 在请求后拿到的就是服务端(Server Side)经过数据请求脚本渲染以后的完整文档,由于它不强依赖客户端的能力,具有更加稳定的性能和较好的用户体验。

为了提升淘宝外、特别是中低端机用户的浏览体验,我们对自定义商详进行了 SSR 化探索,完成了 Rax 多页应用向 Rax 全栈应用的改造,以下是我们的改造历程。

代码结构

项目现在的 Rax 多页应用体系和目标体系 Rax 全栈应用都基于 Rax 框架,目录结构比较相似,全栈应用在多页应用的基础上增加了服务端渲染函数和FaaS相关 工程配置。Rax 多页应用的目录如下:

├── src
│   ├── app.json                    # 路由及页面配置
│   ├── components/                 # 自定义业务组件
│   ├── pages/                      # 页面
├── build.json                      # 工程配置
├── package.json
└── tsconfig.json
Rax 全栈应用目录如下:
├── src
│   ├── apis                      # 函数源码
│   │   ├── configuration.ts
│   │   ├── lambda/               # 接口
│   │   ├── render                # 渲染函数目录                       
│   │   │   ├── home/             # 渲染函数,需与 pages 里的页面名一一对应       
│   │   │   └── ....../  
│   │   └── typings/              # 数据类型定义
│   ├── pages                     # 页面      
│   │       ├── home/   
│   │       └── ....../   
│   ├── document/                 # 文档结构
│   ├── app.json                  # 路由及页面配置
│   └── typings.d.ts
├── build.json                    # 工程配置
├── f.yml                         # 函数平台配置
├── midway.config.ts.             # midway 配置,主要指定接口和渲染目录
├── package.json
└── tsconfig.json

从目录来看,承载页面渲染的核心业务逻辑如 pages、components 都无须改动。SSR 模式下,服务端返回的不再是空文档,而是经过一次渲染后的文档框架,所以需要保持代码在 Node 环境下可运行。由于汽车商详在 Rax 多页应用开发时没有这种环境约束,因此对技改提出了环境模拟的需求,这点在后面会着重提到。

数据请求

CSR 模式下,进入页面后拉取主接口数据,执行 js 完成页面渲染。SSR 下,主接口数据需要在服务端获得,完成服务侧的文档渲染。

97e4ddee-a38d-11ed-bfe3-dac502259ad0.png

客户端得到的只是一个干文档,需要再次执行一遍 js 以激活文档的事件监听、状态传递等,成为可交互的页面,这个过程也有一个形象的名称,叫注水(hydrate):

97f664e2-a38d-11ed-bfe3-dac502259ad0.png

请求流程的转变

由于请求时机的改变,请求及其前后逻辑需要移至服务端执行。

汽车商详基于自建的一套端到端的渲染方案(XRoot)进行接口设计和页面渲染。接口数据中是组件集,包括各组件名称和对应组件需要的 props。我们封装了一套 XRoot 组件,自动执行接口请求、数据注入、页面渲染等工作。

在商详首页中,该接口请求的工作并不只是数据拉取与注入,还承担了一系列请求前后的业务逻辑(如设置全局变量、容灾处理等)。对其中逻辑进行抽象归纳,将业务逻辑聚合到 beforeRequest 和 afterResponse 中:

98175968-a38d-11ed-bfe3-dac502259ad0.png

SSR 模式下,主接口请求在服务端执行,其执行逻辑为:

9826d488-a38d-11ed-bfe3-dac502259ad0.png

afterResponse 逻辑中有一部分是对数据本身的处理,留在服务端实现。另一部分是 UI 相关的,需要在客户端 Hydrate 阶段再次执行。

中间层网关的模拟实现

在阿里集团内,移动端接口和后端的交互会经过了一层 MTOP 网关。MTOP 网关提供了协议解析、安全防护、稳定性保障等能力。SSR 模式下,服务端的数据请求无法经过这层网关,而是直接访问后端 API。

此时业务依赖到的相关 MTOP 能力需要业务侧在 SSR 下手动补齐,其中直接影响页面渲染的就是 MTOP 对接口中空数据的处理:

9843a5fe-a38d-11ed-bfe3-dac502259ad0.png

原始接口数据中值为 null 的属性都被 MTOP 层处理过了,如果 SSR 不做空值属性的删除,前端的默认取值就会出问题:

const { text, tip = '默认提示' } = tagsList[0];
console.log(tip); // 非空处理前:null ;非空处理后:'默认提示'

这里写一个简单的工具函数来做这件事:

export const deleteNullProperties = (obj: Object | Array) => {
  const memory = new Set();
  const fn = (obj) => {
    if (memory.has(obj)) return obj;
    if (['[object Object]', '[object Array]'].includes(Object.prototype.toString.call(obj))) {
      for (const [key, value] of Object.entries(obj)) {
        if (value === null) {
          delete obj[key];
        } else {
          obj[key] = fn(value);
        }
      }
    }
    memory.add(obj);
    return obj;
  }
  return fn(obj);
}

另外,MTOP 网关还提供了用户登陆态的解析与传递,SSR 侧也需要业务自行从 cookie 中读取用户登陆信息

环境模拟

一般来说,由于服务端和浏览器端环境的差异,在做前后端同构应用的时候,开发者都会自觉注意环境差异,避免在不恰当的时机访问浏览器对象,导致 SSR 侧报错。

但是由于本次是改造项目,历史项目只关注 CSR 场景,不可避免地充斥着预期以外的 DOM/BOM 访问,此时有以下几种解决方案:

987be2ca-a38d-11ed-bfe3-dac502259ad0.png

从改造成本和维护成本来看,借助框架能力和引入社区方案是两种可以低成本探索的思路。

框架能力

Rax 全栈应用框架本身提供了在服务器端模拟浏览器环境的能力,从而来尽可能保证 SSR 和 CSR 编码的一致性。其环境变量模拟的基本原则是:

  1. 所模拟的信息可由服务端数据推导得出,例如 location、navigator。

  2. 所模拟的信息不会引起代码执行逻辑的错误,例如对 localStorage 的模拟。

从中可以看出,框架模拟能力并不旨在进行环境模拟,相反它还在试图为页面提供一些真实有用的信息。因此框架提供的模拟能力相对有限,一些常用方法也没有空方法占位,如试图调用 window.addEventListener 时会报 undefined 错误。

由于 Hydrate 阶段的存在,我们的目的只是希望代码能够在服务端不报错,客户端侧的二次渲染会提供更加准确的信息,框架能力并不能满足需要。

jsdom-来自社区的服务端环境库

jsdom 是许多 Web 标准的纯 JavaScript 实现,特别是 WHATWG DOM和HTML标准。该项目并不是为了模拟服务端环境而存在,它的主要目标是模拟足够多的 Web 浏览器子集,使得页面可以在服务端运行,从而测试和抓取真实世界的 Web 应用程序。 98b26980-a38d-11ed-bfe3-dac502259ad0.png  它对浏览器环境强大的模拟能力可以帮助我们避免对项目源码的改造。 由于 jsdom 同样追求对功能性的模拟,功能强大的同时,在服务端运行时可能出现预料之外的问题,需要详尽测试。在使用 jsdom 时,也遇到了一些版本兼容问题,可以通过降低库版本和动态加载等方式解决。

其他问题

降级策略

Rax 全栈应用框架采取中间件降级策略,SSR 侧有任何报错都会自动将空文档返回给客户端,由客户端发起数据请求和渲染,即降级为 CSR。

98e7fad2-a38d-11ed-bfe3-dac502259ad0.png

降级逻辑

99093382-a38d-11ed-bfe3-dac502259ad0.png

降级中间件源码

业务侧也可以根据需要使用框架提供的 useCSRRenderer 钩子函数进行主动降级:992b1196-a38d-11ed-bfe3-dac502259ad0.png

自闭合标签问题

习惯了 react 的 JSX 语法体系,我们通常会写出许多自闭合标签以提高可读性和代码整洁性:

// 自定义组件的自闭合



// 原生标签的自闭合

但事实上 HTML 规范并不支持对

的解析,以一个简单的 demo 为例:

995a3a66-a38d-11ed-bfe3-dac502259ad0.png

在开发者的期待里,b 和 c 同级,d 是 c 的子标签。但实际渲染结果中,c 成了 b 的子级。 对这种情况的一种表象理解是,浏览器把自闭合标签当作正常
头处理,为其匹配了一个
。到最后闭合标签不够用了,浏览器自动加了两个
,导致文档结构发生了变化:

997305be-a38d-11ed-bfe3-dac502259ad0.png

为什么在 JSX 中写自闭合标签能够得到期待中的结果呢?事实上是 CSR 框架侧帮我们做了这件事,如 react 在其官方文档里就有提到:react地址:https://react-cn.github.io/react/tips/self-closing-tag.html 9982eb46-a38d-11ed-bfe3-dac502259ad0.png

从实践来看,Rax 框架在 CSR 侧的渲染同样做了类似的处理,但是 Rax 全栈应用的服务端渲染没有,其 SSR 侧生成的文档只是简单将自闭合标签原样返回:

9993b462-a38d-11ed-bfe3-dac502259ad0.png

不同阶段下的文档结构

由于在 hydrate 阶段浏览器判断 ssr 文档与客户端预期不一致时,会被丢弃掉重新渲染,所以这种处理没什么功能性问题。只是这样就失去了 SSR 的首屏优化功能。在 Rax 团队完善自闭合标签问题之前,业务侧需要避免写出非自定义标签的自闭合。

与 CSR 仓库的功能同步

因为我们是对 CSR 项目的改造,为了不影响线上功能,另启了一个应用仓库。随着改造的进行,原 CSR 项目也一直在接新需求不停迭代。 借助 git merge --allow-unrelated-histories 机制,我们在代码同步方面不必投入太多成本。但是为一个业务场景维护两套应用,其中需要付出的沟通、维护、测试等成本还是很高。

下一步计划

如前所述,两个应用的维护成本较高。因为两者的框架基础是一致的,我们就希望将两个应用合并起来,至少能降低一点代码同步和沟通成本。与技术支持同学沟通了一下,发现没有这个先例,可能会有很多意料之外的问题,所以这部分仍在试错中。

小结

借着本次服务端渲染(SSR)改造升级的实践,我对前端的渲染机制也有了更深入的理解。虽然 SSR 相较于 CSR 有着许多优势,却未成为 Web 渲染的主流模式,是因为构建 SSR 应用并不轻松:需要熟悉服务端开发、了解服务端和客户端的环境差异、服务部署、服务器运维等,对前端开发提出了更高的要求。

而云原生基础设施的蓬勃发展、Nodejs FaaS 函数服务建设的逐渐完善,都将大大降低 SSR 应用的接入门槛。前端开发者将只需关注业务逻辑就能轻松获得 SSR 能力,用户也更有机会得到更好的交互体验。

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据
    +关注

    关注

    8

    文章

    6599

    浏览量

    87963
  • 函数
    +关注

    关注

    3

    文章

    4151

    浏览量

    61560
  • 代码
    +关注

    关注

    30

    文章

    4603

    浏览量

    67386

原文标题:天猫汽车商详页的SSR改造实践

文章出处:【微信号:OSC开源社区,微信公众号:OSC开源社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    马云发话:双十一,淘宝要突破一千亿(13亿人的舔屏时代)

    摘要 :去年双十一天的成交额是571亿,而今年马云更是花尽各种心思,马云发话:今年双十一,淘宝突破一千亿!!!去年的双十一,是平
    发表于 11-11 19:29

    618粉丝狂欢节-haier和联专卖店

    `  粉丝狂欢节是一年一度的618年中大促活动。作为商家:haier和联专卖店,我们不说话、只比价、更有精美大礼相送。海量商品,一站购齐。品牌直营,正品保障,安全便捷!`
    发表于 06-16 14:33

    、泰捷盒子哪个更好用?深度解析四大差异点

    ``、泰捷盒子哪个更好用?深度解析四大差异点 说到电视盒子,、泰捷盒子是目前最畅销的两大品牌,但是很多新手用户并不清楚,它们的核心功能以及定位等,究竟有什么区别,一不小心买到不
    发表于 08-25 16:07

    枯木:双11项目组织协同

    摘要: 2018第二届研发效能嘉年华峰会,云效邀请技术部高级技术专家吴建和(枯木)带来题为双11项目组织协同的演讲。主要内容是从四个方面进行讲解的,首先详细介绍了项目的特性,然
    发表于 06-07 18:00

    ar识别什么意思

    `  谁来阐述一下ar识别是什么意思?`
    发表于 08-28 17:49

    Lua游戏开发实践指南 -

    Lua游戏开发实践指南 - 章.pdf
    发表于 01-14 16:13 29次下载

    vivo与成立“新机研究所”,借助数据造手机

    vivo宣布借助大数据造新手机,联合成立“新机研究所”。不仅借助大数据,消费者还能
    发表于 08-02 17:16 633次阅读

    夏天,改造上网,MODEM改造

    夏天,改造上网,MODEM改造 关键字:散热改造 作者:非诚勿扰—唐少 这几天,。。。。。天气。。。。真的。。。好热。。
    的头像 发表于 09-20 18:54 498次阅读

    魔盒3评测 轻薄同样有实力

    又到了一年一度的双十一,众多厂商都在为这个购物狂欢节不断增加自身竞争力。魔盒当然也不例外,本次双十一,魔盒推出了多款新品,包括
    的头像 发表于 11-15 09:19 6995次阅读

    阿里战略组织架构再调整 将变得更大

    11月26号,阿里公布了一年一次的组织架构调整。阿里CEO张勇发布公开信,宣布阿里最新一次组织升级:阿里云升级为阿里云智能;升级为大,形成天
    的头像 发表于 11-26 17:31 3343次阅读

    京东店关闭 HTC否认放弃手机业务

    近日,有网友发现,HTC手机旗舰店和京东旗舰店已经关闭。其中,平台上的官方旗舰店已无法打开,京东平台上则无法搜索到。
    的头像 发表于 05-12 09:33 2733次阅读

    “618”开卖46秒服饰破亿

    6月1日,“618”第一小时就迎来开门红。0点刚过仅仅46秒,服饰就破亿,开卖7分钟,销售破10亿,同比增幅高达40%。
    的头像 发表于 06-04 14:28 2815次阅读

    V榜TOP100:海尔56度C、美的、格力均上榜

    3月2日,#V榜出书了#登上微博热搜TOP3,受到网友极大关注。从话题上看到,这是首本官方购物指南《
    的头像 发表于 03-04 12:43 2583次阅读

    否认“大数据杀熟” 部分用户不买账联系消协

    但在刚刚过去的超市的“38节”活动中,有网友发现,超市同一款商品对不同用户的售价不一
    的头像 发表于 03-12 16:17 2144次阅读

    魔盒实际性价比怎么样,现在值不值得买

    魔盒是这个平台主推的电视盒子产品,很多人最开始买电视盒子的时候都会考虑到魔盒,那么
    的头像 发表于 02-17 17:20 1.1w次阅读
    <b class='flag-5'>天</b><b class='flag-5'>猫</b>魔盒实际性价比怎么样,现在值不值得买