作者 | 优酷前端技术团队
在2017年底,优酷只有Passport和土豆的部分页面用Node.js,PC和H5核心页面还都是PHP模板渲染。而最近2年,基于阿里巴巴的技术体系,我们对PC、H5多端进行了技术改造。在2019年,React SSR第一次且成功地扛起双11重任,具有一定意义。
本文将对这一技术演进之路进行总结和展望,有2点突出变化:
1) 我们将优酷C端核心页面全部用Node重写,完成了PHP到Node.js的迁移。在没有PHP同学的情况下,前端可以支撑业务;
2)从Bigpipe+JQuery到React SSR,性能明显提升。PC页面首屏渲染降到150ms、播放器起播时间从4.6秒优化到2秒。H5站上了React SSR后,性能提升3倍。
演进之路
优酷前端团队在之前 PC 首页/频道页面改造的基础上,将 React 服务端渲染沉淀出了一个技术框架,该项目已经在 Github 开源,截止目前已有 900+ star,具体使用方式和源码请查看egg-react-ssr项目地址。
第一版:Bigpipe + jQuery
核心还是采用Bigpipe + Nunjucks模板编译实现的。模板tpl和data编译,生成html,这个部分其实Biglet的render方法里做的。然后在请求写入的生命周期上,将html分块写入浏览器。
1)采用Bigpipe有2大核心优势:
- 兼容IE6等低版本浏览器,不得不用。现代Web框架只支持主流浏览器。之前开发对jQuery都比较熟悉,二者结合是当时最完美的选择;
- 业务属性决定的,新老接口拼凑(PHP的,Java的,HTTP的),采用Bigpipe,利用Node.js并发,将接口请求从前端转移到服务端,即可以保证业务快速迭代,也可以保证页面性能;
将页面进一步抽象,以前理解是每个模块都Biglet。但实际使用中,进行分级处理会更好。
- 首先渲染布局;
- 核心:渲染首屏,对于播放页重点是播放器和剧集内容;
- 其他:看不到的可以偷偷加载,及时不展示也没问题;
2)性能
当前:React SSR
采用React SSR,是在Node.js Bigpipe做了一些之后才考虑的。稳定性有了,低版本浏览器兼容有了,接下来就要考虑团队成长和架构升级的问题。
- 会JQuery,不会React,大家是非常想用想学的;
- Bigpipe虽好,但依赖模板编译,在内存和CPU使用上非常高,优化不易;
- 老系统慢慢下掉,之前混着新老接口一起用的方式也需要重新梳理。为了快速迭代而产生的“狗粮”还是要吃的;
其实,如果把React当模板,结合Bigpipe,可以达到和之前解决方案一样的效果。问题不能很好的利用React的优势,React自身也提供SSR基本能力。所以,我们需要做的是如何结合React的SSR,构建出符合业务特点的SSR框架。
组件级同构: 支持 CSR/SSR 一键切换
在技术调研期,我们分别看了next.js和easywebpack。
- easywebpack在使用上,我不认可使用egg的worker来做。easy-team的方案本地开发采用了在Node中启动webpack编译bundle的方案,将服务端bundle打包在内存中,agent进程通过memory-fs提供的api来读取文件内容,并且通过worker与agent进程的通信,来让worker进程可以获取到文件的字符串内容。然后采用了Node的runInNewContext api,类似于eval的方式去执行js字符;
- next.js写法上是完美的。结合上面讲过的Biglet,请求方法抽取成静态方法,可以复用。另外在服务端渲染,先执行请求方法,是最高效的方式;
写法上,最终定了采用next.js式的写法。
该技术方案具有以下优点:
- 实现方式简单优雅
- SSR/CSR 无缝切换
- 全面拥抱 JSX
- 拥抱阿里生态
我们的代码既可以在服务端运行又可以在客户端运行。这里需要重点讲一下CSR和SSR,我们是业内第一个这样做的。它也带给我们一个意外惊喜,那就是在服务降级上提供了一个更好的方案。
播放页的服务支持两种渲染方式,当服务端有渲染压力时或集群不稳定时,可以切换为客户端渲染,服务端只负责页面的 SEO 数据获取,渲染工作交给浏览器。另外一种方式是当数据源服务出现问题时,可以使用 CDN 数据兜底进行页面容灾。
3组件: 多模块升级配合改造
播放页的页面组件包括首屏、分发区、弹幕、播放器、评论等等一系列的组件,此次播放页升级对应的组件也做了重构,其中弹幕、评论已随新版播放页一起灰度上线。
服务端 JSBundle 发布: 变更无需发布应用
在 SSR 改造中我们总结出了一套基于配置下发的服务端和客户端文件的流程。该流程有以下优点:
- 构建方式一致
- 发布方式一致
- 服务端 bundle 变化无需走服务端发布
- 及时生效
下面是发布的流程图:
性能对比
以预发版本播放页为例,使用 chrome 无痕模式测试。
优酷PC播放页:150ms首屏,首屏文档大小37kb。文档到达时间平均为 120ms。
优酷H5播放页性能提升3 倍。
未来:Serverless SSR
从beidou、next.js、egg-react-ssr到Umi SSR,可以看出服务端渲染是很重要的端侧渲染组成部分。无论如何,React SSR都是依赖Node.js Web应用的。那么,在Serverless时代,基于函数即服务(Functions as a Service,简写为FaaS)做API开发相关是非常简单的:1)无服务,不需要管运维工作;2)代码只关系函数粒度,面向API编程,降低构建复杂度;3)可扩展。
在FaaS下,如何做好渲染层呢?直出HTML,做CSR很明显是太简单了,其实我们可以做的更多, Serverless时代的渲染层具有如下特点:
- 采用next.js/egg-react-ssr写法,实现客户端渲染和服务端渲染统一;
- 采用Umi SSR构建,生成独立umi.server.js做法,做到渲染;
- 采用Umi做法,内置webpack和React,简化开发,只有在构建时区分客户端渲染和服务端渲染,做好和CDN 配合,做好优雅降级,保证稳定性;
- 结合FaaS API,做好渲染集成。
通过提供ctx.ssrRender方法,读取dist目录下的Page.server.js完成服务端渲染。
核心要点:
- ssrRender方法比较容易实现;
- 采用类似Umi SSR的方式,将源码打包到Page.server.js文件中;
- 在发布的时候,将配置,app.server函数和Page.server.js等文件上传到Serverless运行环境即可。
综上所述,我们大致可以推出架构升级的4个阶段。
- 在CSR中,开发者需要关心React和webpack;
- 在SSR中,开发者需要关心React、webpack和egg.js;
- 在Umi SSR同构中,开发者需要关心React和egg.js,由于Umi内置了webpack,开发者基本不需要关注webpack;
- 在未来,基于FaaS的渲染层,开发者需要关心React,不需要关心webpack和egg.js。
在这4个阶段中,依次出现了CSR和SSR,之后在同构实践中,对开发者要求更高,甚至是全栈。所有这些经验和最佳实践的积累,沉淀出了更简单的开发方式,在未来Serverless环境下,希望前端更加简单、高效。
规范
实现
生态
致敬所有多端坚守者
感谢苹果,将用户体验提升到了前无古人的位置。移动互联网兴起后,PC Web日渐没落。在AI时代,没有“端”的支持可以么?明显是不可以的。不只是“端”的概念,而是真真正的用户体验。
1)我们可以利用PC/H5快速发版本的优势,快速验证AI算法,继而为移动端提供更好的模型和数据上的支撑;
2)多端对齐,打好组合拳。既然不能在移动端有更大的突破,大家只能在细节上血拼。按照木桶原理,哪个地方是短板,整体水位就在那里。
今天的大前端,除了Web外,还包括各种端,比如移动端、OTT,甚至是新的物联网设备。我们有理由相信Chrome OS当年的远见:“给我一个浏览器,我就能给你一个世界”。
好书推荐:
前端代码是怎样智能生成的
关注「Alibaba F2E」
回复 电子书,立即下载