作者简介
Frank,携程前端研发,专注前端性能优化、一码多端、工程化建设等领域。
一、业务背景
随着移动互联网和智能设备的普及,前端开发人员需要采用多端同构技术来适配不同的终端(小程序、App和Web)。这些终端之间存在着明显的差异,包括浏览器引擎、操作系统、交互方式以及代码语言等方面。
这些差异给前端开发人员带来了不少挑战。一方面,不同终端采用不同的浏览器引擎和操作系统,导致页面渲染和交互行为的表现各不相同。另一方面,不同终端所使用的代码语言和开发工具也存在差异,需要开发人员具备不同的技术背景和知识,才能编写多份代码来适配不同的终端。这样做不仅增加了研发人员的开发工作量和代码维护的难度,还可能导致用户在不同设备上遇到不一致的用户体验,影响产品的质量和用户满意度。
为了解决这些问题,多端同构技术应运而生。通过多端同构技术,旅游前端和公共团队合作多端探索与实践,根据不同终端的特性进行灵活的适配和定制。这样可以减少开发成本和维护难度,提高开发效率和代码的可复用性。同时,多端同构技术还能提供一致的用户体验,无论用户使用哪种设备访问应用程序,都能获得相似的界面和功能。
行业现状
三端同构
二、多端同构技术选型
在进行多端同构技术选型时,我们需要综合考虑跨端能力、成本、性能、代码语言通用性以及现有技术的支持度。这将有助于我们选择最适合的技术方案,以下是对当前前端主流跨端技术的分析:
Hybrid | React Native | Flutter | Weex | Taro | |
跨端能力 | ★★★★ | ★★ | ★★★ | ★★★ | ★★★★ |
成本 | ★★★★ | ★★ | ★★ | ★★ | ★★★ |
性能 | ★ | ★★★ | ★★★★ | ★★★ | ★★★ |
代码语言通用性 | ★★★★ | ★★★★ | ★★ | ★★★ | ★★★★ |
携程支持度 | ★★★ | ★★★★ | ★★★★ | ★ | ★★★★ |
Hybrid:使用JavaScript语言,支持快速构建多端应用。由于依赖于Webview容器来运行,所以其用户体验和性能受到一定的限制的。这种限制会导致应用的响应速度变慢,页面加载时间变长等问题。适用于三端业务述求比较高,研发成本又比较低,性能要求不高场景,比如营销广告页。
React Native:使用JavaScript语言开发的React的组件,支持构建App、Web,不支持原生小程序。App上有接近原生应用的性能和用户体验。适用于对小程序性能要求不高的场景。
Flutter:使用Dart语言和自带的渲染引擎,支持范围同ReactNative。在渲染速度和用户体验方面表现比ReactNative更加出色。由于ios平台规则限制,目前对于热更新支持并不友好。适用于对App性能要求较高,小程序性能要求不高的场景。
Weex:使用JavaScript语言开发的Vue的组件,支持范围与性能同ReactNative,社区活跃度不如ReactNative。
Taro:开放式跨端跨框架解决方案,它提供了一套统一的开发语法和组件规范,使开发人员能够使用一套代码来开发适配不同平台的原生应用程序。适用于对于三端述求高,性能要求也高的场景。由于设计之初是面向小程序的,所以规范上对ReactNative研发来说并不友好。
考虑到我们业务对于多端和性能的要求都很高,结合现有团队技术储备能力,所以选择Taro多端同构技术方案。在本文中,我们会重点讲述旅游事业部门票活动前端团队和公共无线技术团队合作将Taro技术栈与现有技术进行融合后,遇到的问题以及相应的解决方案。
三、Taro如何与现有技术融合
Taro提供的多端同构技术,在不需要考虑与现有技术栈的结合的前提下,是可以直接使用的。针对本身已有一套技术方案情况,就需要考虑如何将Taro与现有的App或Web技术进行融合。
Taro跨端方案是基于静态编译的解决方案,最终生成的是将源代码编译为目标代码并打包成可执行的文件。该文件既不能直接集成到业务方(携程)RN、Web的框架中,也不能直接调用携程提供的业务组件,如城市、日历、支付等。因此,开发者需要对Taro进行适配后,才能解决与现有框架融合的问题。
如上图,Taro的核心原理是在编译构建时通过注入自定义配置,将原本的小程序组件和API替换为适应不同平台的组件和API,从而实现多端能力。这样一来,业务开发中可以使用相同的代码来适配不同的终端,消除多端开发中的差异。
3.1 融合App(与携程React Native技术融合)
1)在Taro的配置文件中,注入自定义plugins插件
2)通过Metro打包配置,进行别名替换(原有的taro引用替换成新的RN路径)
3)抹平Taro的组件和APIs方法
Text组件
页面跳转API
按照以上步骤,并且结合ReactNative的脚手架,就可以运行起来。
3.2 融合Web(与携程NFES技术融合)
Taro同构技术已在Web端的非SSR和SSR模式。SSR模式是以NextJS框架未基础的,通过提供编译插件tarojs-plugin-platform-nextjs来支持。但由于这个编译插件并不支持基于NextJS技术扩展的Web框架或其它Web框架,所以需利用Taro脚手架中开放的编译能力,在构建时通过babel插件将APIs和组件库替换为支持服务端同构的版本,同时生成适配当前框架的目录及项目配置,使得Taro具备转换为对应Web框架的能力,具体参考如下步骤:
1)同RN,注入自定义H5 plugins插件
2)通过Webpack打包配置,进行别名替换
3)抹平Taro的组件和APIs方法
Text组件
页面跳转APIs
4)根据自身框架的调整路由、中间件等项目配置,以下是携程NFES示例图
按照以上步骤,并且结合自身Web的脚手架,就可以运行起来。
四、技术实践
在解决好Taro多端框架与现有技术融合的问题之后,还需要进一步完善组件和API的丰富度,提升应用程序的性能,并解决CSS适配的问题,以实现降低开发成本和提升用户体验的目标。
4.1 组件库与API
1) 组件和API丰富度
Taro多端同构技术的核心方案是通过抹平组件库和API差异,实现跨端同构,从而使得性能和用户体验与独立开发单一端的应用程序相一致。然而,这种方法的不足之处在于需要开发各端的组件库和API,以与Taro小程序相对齐,这需要较大的初始成本。
Taro多端设计时已考虑到了降低研发人员首次投入的成本,所以提供对齐Taro小程序的组件库和API,共计60多个。经过实践验证,已满足大部分常用的业务需求。
除了已提供的组件和API外,仍旧需要开发面向业务的扩展组件和API,例如,弹层、折叠、日历和城市选择等组件以及支付、登录等(如上图)。大部分组件只需要在官方提供组件上做二次封装,研发成本不大。
2) 多端组件和API差异性
多端组件和API在不同平台上可能存在一些差异,无法完全抹平。每个平台有自己的特性和限制,因此在开发多端应用时,需要对这些差异进行适配和处理。
比如在动画实现方面就存在不同平台之间的差异。在ReactNative中,只能使用Animation组件来实现动画效果,在小程序和Web端是使用CSS样式来实现动画效果,为了尽量保持多端一致性,将动画实现封装成一个统一的组件,以便在不同平台上使用。封装后的动画组件,在RN端调用的是Animation组件,在小程序和Web端则使用组件内通过Js添加Css样式来实现动画。这种方式解决了动画实现的差异性,使得开发人员可以通过使用统一的接口来调用动画效果,无需过多关注不同平台的具体实现细节。
把以上遇到抹平问题,可以归纳为以下3类情况:
情况说明 | 解决方案 | 例如 |
A,B端都有此功能但差异不大 | 抹平差异 | input、路由跳转等 |
A,B端都有此功能但差异很大 | 抹平差异 | 动画组件封装成统一API |
A端有此功能但B端没有 | 降级抹平差异或差异抹平 | 差异抹平:各端实现各端,如RN使用Flatlist,其它端使用scrollview 降级抹平:有的显示,没有的不显示,如头部导航栏不存在小程序中 |
4.2 CSS适配
CSS的跨端支持性是较弱的,受限于ReactNative的平台限制,所以支持并不友好。
ReactNative不支持CSS样式的嵌套。只能将样式拆分成多个独立的对象,并通过StyleSheet.flatten方法将它们合并成一个对象,从而实现在一个层级节点上设置独立样式。目前只能通过差异抹平适配多端方法,牺牲其他端CSS灵活性。
ReactNative不支持CSS中的伪元素选择器。如::before和::after,因为它没有DOM元素并且不支持这些选择器。可以通过添加HTML节点来适应选择器写法。
上述的写法限制了多端开发的效率,但并不影响产品的功能实现。另外一些样式等问题,大部分可以使用Babel插件(如rn-style-transformer)来抹平。
平台默认属性差异
属性 | ios-rn | android-rn | web | 小程序 |
fontSize | 14 | 16 | 16 | 16 |
color | #000 | #777 | #000 | #000 |
margin | 0 | 0 | 8 | 0 |
padding | 0 | 0 | 1 | 0 |
平台属性支持差异
属性 | ios-rn | android-rn | web | 小程序 |
background | 不支持 | 不支持 | 支持 | 支持 |
position:fixed | 不支持 | 不支持 | 支持 | 支持 |
textIndent:number | 不支持 | 不支持 | 支持 | 支持 |
dashed | 不支持 | 不支持 | 支持 | 支持 |
4.3 性能
Taro由于采用的是静态编译时生成平台代码,所以性能优于动态编译时生成的方式。在App端性能和原生RN性能相当,但是在Web端会将Dom节点替换为Web Component,而Web Component的渲染能力相对于原生组件较低。因此,如果在转换过程中,如果存在大量Web Component,会导致页面渲染的变慢。在电脑型号为MacBook Pro(14英寸,2021年),浏览器型号为chrome,浏览器版本为113.0.5672.63(正式版本)(arm64)的测试条件下,以taro-view-core(View)组件为例,重复渲染2000次,总耗时大约在123ms。如果换成div重复渲染2000次耗时大约在17ms,大概相差7倍左右,实验截图如下:
Web Component耗时:
原生div耗时:
从以上实验可以得出,不要直接使用 Taro 提供的 View 和 Text 等组件,而是在 Web 原生组件上再包一层具备 Taro 功能的组件。
五、 适用场景和成本
5.1 View层同构
根据交互和产品设计的需要,对于App、H5、小程序交互方式相似度大于70%建议可以采用一套View,差异部分可以用Taro工程提供的文件扩展名方式实现各自的差异部分。
由于 PC 端的交互方式差异较大,因此通常需要编写两套View组件,这样做比较合适。
5.2 多端同构适用场景
多端同构适用于需要在多个平台上提供相同功能的应用程序,达到提高开发效率和用户体验的目的。
不适用于对性能要求较高以及高度依赖平台的专属特性的应用程序,比如基于canvas制作的游戏,对于不适用场景且多个平台都需要支持的话,只能各自实现各自效果。
5.3 多端同构的成本
尽管多端同构技术可以减少开发的成本,但不同平台之间仍存在样式和API的差异,需要研发人员进行适配和补充。实际各端的研发成本对比可参考下表:
研发成本 | 多端同构后 | 备注 | |
App | 1 | 0.2 | |
H5 | 1 | 0.2 | |
小程序 | 1 | 1.2 | 先开发的平台 |
PC | 1 | 0.4 | |
总计 | 4 | 2.2 |
随着开发经验的积累和组件的丰富化,研发和测试成本也会进一步降低。
学习成本:多端同构开发需要研发人员具备跨端开发的能力和经验,需要了解各个平台的特性和差异,同时还需要关注代码的性能、可维护性和可扩展性等方面。我们可以通过多种培训和分享来提高他们的能力和技能。
测试成本:在多端同构的开发模式下,如果不慎改错一端会影响到所有端,所以测试成本会增加。测试范围更广,测试时间也会更长,因此测试成本也会相应地增加。另外,由于不同平台之间的差异,测试人员需要具备跨平台测试的能力,这也会对测试人员的研发能力提出更高的要求。为了解决这些问题,可以普及 UT(单元测试)和 AT(自动化测试),这可以降低测试成本,提高测试效率。
生产稳定性:因为多端同构技术采用的是统一的代码逻辑和组件封装,一旦出现问题,多个平台都会受到影响。因此,在开发过程中需要进行严谨的测试和质量控制,以确保代码的稳定性和可靠性。
六、总结与展望
本文介绍的是通过使用Taro实现多端同构,在跨多平台业务场景中降低研发成本,提升用户体验。通过使用同一开发语言和代码框架,实现在不同端上复用代码,达到统一业务逻辑的目的。
可以预见在不久的将来,无论是基于业务需求还是技术实践与创新,都将出现更多的解决方案,使得多端开发之路变得更加平坦。同时,这套方案将成为公司主推的多端框架。