优酷客户端是一个多平台【Phone、Pad、OTT、MacPC】的文娱生态综合体,为了降低多端产品迭代的开发成本,并提供给用户高性能、一致的产品体验,优酷技术团队在19年底启动了跨平台动态模板引擎技术方案的攻坚。
作为内容分发的主体,优酷客户端在产品展现层的主要特点是组件设计的规范化和卡片化。优酷动态模板引擎在问题定义上将组件作为了我们的问题空间模型,不仅很好的规避了如Weex、React Native等技术方案的复杂度和工程量,让我们可以快速实验及工程化。其次也在根本上让技术方案脱离JS Bridge的老路,保证了端侧的高性能。
组件化在目前的移动端来说是非常常见的组件UI形态,在优酷客户端的分发场景中,组件则更多的承载了影剧综漫等内容的信息呈现。
当然,组件本身可以通过组合或嵌套来形成更加复杂的展现模式,但从原子化角度来讲,作为单一元素来看,组件有着非常强的结构化特征,抽象后其逻辑构成如下:
1.视觉元素:控件,图片、文本、富文本等
2.布局:视觉元素的位置控制信息及元素绘制样式信息,如坐标及字体、字号等
3.数据:要真实表达给用户的有意义的信息,如影剧综漫的名称、演职员、封面海报等
4.事件:对用户交互的反馈及逻辑响应,如点按钮收藏、预约、关注等
所有的原子化组件都可以抽象为上述的元数据,那如何把这套数据结构进行有机组合形成模板,并在多端场景按照同样的行为表现进行渲染,是本篇文章要详细进行阐述的内容。
在概述中介绍到,我们可以将原子化的组件抽象为元素、布局、数据、事件四类核心信息,其中元素信息,我们通过JSON数据结构进行组织,来描述组件中的元素构成及层级关系;布局信息中布局关系通过符合css3规范的flexbox盒模型进行描述,样式信息则通过标准化的css来进行描述;数据模型引入了XPath的理念,由于组件元素中最终呈现的数据往往来自云端下发的JSON数据,因此,这部分要解决的是如何将组件中文本的text属性与云端JSON数据中某个层级的data实现动态绑定,类似于root.path.router.title; 至此,通过将上述数据结构整体组合,打包后形成的一个物理文件,我们称之为模板。 当任一客户端完整实现了对这个模板文件的解析与渲染,便可完成组件的绘制工作,从而实现跨端。
优酷动态模板引擎是由优酷技术团队自研的,提供对上述模板文件进行跨端标准化解析、构建、渲染的客户端技术方案。由于优酷内容分发场景对用户体验和技术性能有极其苛刻的要求,因此,我们制定的所有技术方案的最高前提是性能第一。
动态模板引擎在优酷内部代号为GaiaX,按照分层设计理念共分为4层。基础依赖层坚持最小依赖原则,要重点说明的是,为了保证模板布局计算的高性能,我们引入了由RUST编写的StretchKit高性能布局计算引擎[https://github.com/vislyhq/stretch],其具备跨端、较小的包体积(170K)、计算性能卓越等特点;核心渲染层构成模板引擎的渲染内核,解决模板文件解析、虚拟节点树构建、布局计算、表达式构建解析等核心逻辑;模板中心及模板服务层则更面向业务,与优酷业务架构进行结合实现对现有能力的复用,避免重复造轮子,并向上层业务提供标准化模板渲染及接入服务。
对于动态模板引擎来说,输入结构化的模板文件,经过文件IO、数据解析、虚拟节点树构建、布局计算、表达式运算、渲染树构建到真实视图树组成了完整的总线链路。
虚拟节点是链接模板文件,生成布局,绑定样式,以及最后渲染view的核心模块,整个链路是属于线程安全,可以在在线程进行操作和布局,在生成view的时候回到主线程,可以为后续的预渲染和性能优化提供可靠的保障。
下图是描述index.json通过GaiaNode和视图View的对应关系:
• Node作为基础的虚拟节点,负责CSS中Style信息生成客户端样式属性,以及CSS布局信息通过StretchKit生成的frame布局信息,同时获取父node,以及和子node数组的对应关系。
• Node和View的关系是一一对应的,Node通过creatView的方式创建不同的view视图,以及renderView的方式将样式和frame一次性赋值给view,减少重复的赋值操作。
• 在此基础上根据模板中的视图type衍生出rootNode,viewNode,imageNode,以及textNode。
• StretchKit库的优势
选中Stretch看中的就是其有着极好的性能表现和较高的内存使用率,而这些都是Rust语言特性所带来的。Rust速度惊人且内存利用率极高,标准Rust性能与标准C++性能不相上下,某些场景下效率甚至高于C++。由于没有运行时和垃圾回收,它能够胜任对性能要求特别高的场景。
• AST层级极简
AST即虚拟节点树是根据模板文件构建的逻辑树,其层级结构的合理性完全受制于模板创建者对flexbox布局的熟悉程度,为了提高整体技术方案的性能下线,动态模板引擎在进行虚拟节点树构建过程中,会主动进行层级优化和拍平,从而减少不必要的元素冗余关系,提升渲染性能。
• 线程减负
通过对虚拟节点树进行DIFF运算,当真实存在数据改变时才提交更新处理
减少线程池线程数,避免不必要的并发线程间的资源开销及抢夺
对数据遍历、JSON解析赋值、布局计算等处理进行异步化,保证对于主线程非必要不提交
技术方案 | DSL | 最佳实践 | 胶水层 | 渲染方案 | 研发团队 |
Weex | Vue/Rax | 页面动态化 | JSBridge | Native渲染 | 阿里巴巴手淘技术团队 |
ReactNative | React | 页面动态化 / App整体架构方案 | JSBridge | Native渲染 | |
MTFlexbox | XML | 组件级接入 | 无 | Native组件半异步渲染 | 美团终端业务研发团队 |
GaiaX动态模板引擎 | JSON | 组件级接入 | 无 | Native组件半异步渲染 | 优酷应用技术团队 |
目前在优酷15+业务团队中,均接入使用了动态模板引擎作为跨端提效技术方案;经过自2020年起一整年业务应用,从实际效果来看,对于多端组件开发整体研发效率提升可达30%左右,单组件研发人力投入可由0.5-1人日下降至0.25-0.5人日。
动态模板引擎在优酷业务场景上线后,无论是线上的用户体验、还是研发端的效能度量上都有比较良好的表现。从整个端侧开源社区来看,面向组件级的跨端动态化方案还是比较少的,因此,优酷技术团队在2021年10月决策将方案进行开源,一方面无论是发现issue还是贡献代码,希望通过社区的力量对技术方案实现持续迭代演进,将其打造为功能更加强大的有社区影响力的产品。另外,也希望成熟稳定的技术能力可以帮助更多的个人开发者及中小技术团队,解决客户端日常开发中的痛点问题,实现多赢。
• 项目地址:https://github.com/alibaba/GaiaX
• 开源协议:项目遵循Apache2.0协议
• 项目文档地址:https://www.yuque.com/biezhihua/gaiax
优酷动态模板引擎在优酷整体业务架构中,已经作为分发场基础能力被各业务广泛使用。由于模板DSL是前端技术栈范畴,对于客户端同学来说有一定的学习成本,因此,技术团队在引擎技术能力稳定后的主要研发方向是为使用者提供可视化、搭建化的LowCodeIDE平台能力。目前,该能力也已经交付到各技术团队中,从实际效果来看,对降低模板搭建成本非常有效。在动态模板引擎的开源项目中,IDE本身也进行了同步输出,广大社区开发者可以直接使用平台进行模板搭建。
随着技术方案的开源,团队会根据社区的反馈将开发者关注的问题和能力尽快进行实现,同时,在业务场景孵化的一些新特性,也会实时向社区推出,让更多的开发者受益。
优酷技术团队目前在阿里巴巴开源社区已经开源上线了不少技术方案,后续还将推出更多的能力,也希望广大技术爱好者关注阿里巴巴开源社区(https://github.com/alibaba),关注优酷端侧技术的发展。