W3C

MiniApps 标准会议

2022年9月7日

题目:小程序跨端方案演进之路

讲者:陈嘉健 [演示文稿]

现场纪要

陈嘉健:各位同学,下午好,我是来自京东Taro团队的陈嘉健。今天分享的主题是《小程序跨端方案演进之路》。

如果各位同学看了上午Taro的演示,大概了解Taro的语法以及怎么使用,和它的跨端效果。本次分享会更深入的带大家了解Taro是如何解决小程序跨端开发这个问题。

今天的分享四个部分:首先是介绍Taro跨端开发的背景。接下来回顾Taro1、2和3的演进历程;接下来是整体的展望。

首先是跨端开发的背景。自从微信小程序推出以来,各大厂商的小程序平台层层出不穷,产品的发布渠道也逐渐变多,我们会逐渐接触到一些跨端开发的需求。

但是跨平台开发有很多痛点。我们总结下来主要有三个:一是业务响应不够及时;二是会增加研发成本;三是各平台的代码维护起来非常困难。

因此,当时我们就想能不能只开发一套代码,让这套代码可以跨平台运行,分别运行在各个小程序环境,以及 H5 和原生native环境。

因此我们开发了Taro这套跨平台开发解决方案,开源三年多以来,收到了业界很多的关注,形成了一定规模的开发社区,和业界头部企业展开了不少合作。在公司内外部都有很多可公开的大型应用案例。

Taro框架主要有三个特性:第一,可以让开发者使用前端的技术栈开发出横跨各个小程序端、H5端、React Native等平台的应用。第二,让原生小程序跨平台运行。第三,可以让传统Web应用跨平台运行。

二、Taro1&2 介绍了Taro的特性之后,相信大家也对Taro也产生了一定的兴趣。接下来我会带大家回顾一下Taro发展的历史。

我们认为跨平台开发需要解决四大问题:语法差异、组件库差异、API差异和研发生态复用。

首先看看我们怎么解决语法差异。下面左、中、右分别有三个代码片段,左边是传统的React语法,中间是小程序的语法,它类似MVVM的语法,右边是快应用语法,它是类似Vue SFC的语法。可以看到它们之间的语法差异非常大。

为了解决这一差异,首先要统一开发语法标准。我们需要定义一套前端熟悉的语法规范。当时我们就选择了我们团队比较熟悉的React语法规范。

接下来需要考虑的是如何让React语法跨平台。

具体来说输入一份React源代码,可以通过语法分析、词法分析、语义分析,得出一颗抽象语法数——AST,我们可以对AST进行转换操作,最后输出目标平台的代码。

从输入源代码到生成AST这一步,可以借助babel的功能帮助我们完成,所以我们主要聚焦代码转换这一步。

下面举一个比较简单的例子,下面一个React组件,首先我们需要对React组件的JSX部分(红框部分)进行转换,然后输出小程序平台对应的XML语法。

借助Taro能力我们可以输入一套 React 代码,然后编译为各小程序平台对应的产物。但是,只有这些产物还不够,还不够抹平不同平台语法间的一系列差异。

因此我们还要在小程序的逻辑层提供一个运行时一Taro Runtime,配合编译产物一起抹平差异。

解决语法差异之后,再看看我们是怎么解决组件库和API库的差异。

下面是我挑选了一些比较通用的组件,列举出它们在各个平台的实现,可以看到它们之间的命名和属性都有很大的区别。

接下来,也是一样的,我挑选了部分API,可以看到它们的差异也非常之大。

为了解决组件库和API的差异,我们有必要制定一个标准。

当时我们就选择了发展得比较好的微信小程序,以它的组件库和API库,作为组件库和API的规范。

有了规范后就比较好处理了,我们只需要使用不同平台的原生组件和API去模拟实现微信小程序的组件库和API标准就可以了,例如H5,可以基于浏览器及第三方SDK实现微信小程序标准的组件库和API库,React Native、快应用也是一样,这样就可以API和组件库的问题。

最后看看我们是怎么处理研发生态复用的问题。这里的复用包括了开发生态和构建生态。

过去的Taro1和2支持部分React 的开发生态,包括React-Redux和 Mobx,但它们并不能直接运行小程序端,我们需要对它们魔改一个小程序的版本才可以运行,另外antd-Mobile、React Query等React的常用生态都不支持在小程序应用。

对构建生态来说,Taro2基于Webpack构建了一套编译系统,从而支持使用海量的 Webpack构建生态。

同时Taro2还引入了插件化机制,开发者可以定制自定义的功能。例如扩展命令行命令、编译平台等等,它们也可以把自己的插件发布到开源社区生态里,供更多人使用。

那Taro1和Taro2有没有问题呢?其实我们维护下来有不少问题。主要有三个问题:第一,通过编译的方式,并不能100%的兼容React的语法。React语法是受限,所以很多开发者找过来说为什么这个语法不能使用。

第二,我们不是使用正真的React,所以很难复用React生态。

第三,不支持使用Vue,那很多Vue团队就不能使用Taro的跨平台适配能力。

三、Taro3

为了以上问题,我们就开发了Taro3的框架。

接下来介绍一下Taro3是如何处理Taro1和Taro2的问题。

除了编译的方式,还有没有其他可以处理语法差异的方法呢?

其实是有的。我们回顾React、Vue等等Web端框架,都是使用浏览器提供的DOM和BOM API进行渲染,我们是否可以在小程序端模拟实现浏览器环境,例如实现DOM、BOM API,从而让React真正运行在小程序平台上呢?

答案是可行的。

首先,我们要参照浏览器的标准,实现一套DOM API,当然DOM API不是完全对照标准实现,而是可以让React、Vue框架运行起来的最小集合。

接下来我们需要实现一套BOM的API,例如document、navigator等等,利用Webpack的providerPlugin注入到各模块中,从而供他们使用。

有了DOM 和BOM API之后,就可以构建出一颗基础的DOM树。然后在小程序入口组件触发OnLaunch的时候,我们会挂载开发者的入口组件,接下来触发onLoad的时候会挂载开发者的页面组件。

React完成渲染之后,我们可以在小程序的逻辑层得到左边的Taro 虚拟DOM树。

接下来我们需要把逻辑层动态的DOM树在视图层中进行渲染,但我们在视图层用于渲染的节点,在小程序里需要提前编写一个XML文件。小程序并没有提供动态创建节点的方法,那这应该怎么做?

Taro采用的方法是利用小程序template 模板功能,每个节点会对应一个模板。我们会把DOM树的数据进行序列化,然后传递到视图层,从而驱动视图层的这些模板完成拼接,最终渲染出最终的效果。

接下来,介绍一下Taro3整体的渲染流程。

首先,关注左边逻辑层这部分,用户开发的React或者Vue代码,首先会代用Taro运行时体动的BOM、DOM、API,进行渲染,渲染出DOM树,DOM树会进行序列化,通过小程序的setData API传递到视图层,视图层会驱动模板拼接并渲染出最终的结果。这就是一套完整的渲染流程

那再回顾一下Taro1和Taro2的时候,我们思考当时我们遇到的一些问题,看Taro3能不能解决所有问题。

第一点,Taro3可以运行真正的React,因此它可以100%的兼容React语法。第二,Taro支持使用Vue,因为它模拟实现了浏览器环境,理论上任何的Web开发框架都支持在Taro3使用。第三,我们支持复用大部分的Web生态。

有了Taro3的能力之后,我们又做了一件事叫H5同构,可以把传统的H5应用直接运行在小程序端。以下是我们适配的三个移动端的样式库,它们运行在小程序端的例子的截图。

分别是antd Mobile、Vant UI和WeUI,它们都可以直接在小程序端直接运行。

随着越来越多小程序平台的推出,我们也在不断思考Taro的定位。最终,我们发现Taro应该是一个多平台适配的平台,开发者可以借助Taro的能力,适配各个小程序的平台。

因此,我们重新设计了一个开放式的架构,开发者可以借助Taro的能力,横向扩展出一些新推出小程序的平台适配,他们只要简单编写一个Taro插件,就可以适配到对应的小程序平台,例如快手小程序插件、鸿蒙插件等等,并不需要Taro内部的核心代码,只需要编写一个插件就可以完成一个平台的适配。

除了横向的拓展之外,还可以做一些纵向的拓展。我们可以继承现有小程序插件,编写出一些自定义的插件。例如,我们可以基于微信小程序插件,拓展出QQ小程序插件,基于支付宝的小程序插件,可以拓展出阿里系的小程序插件等等。

简单介绍一下Taro对鸿蒙的适配。

我们编写了一个鸿蒙插件完成适配,具体的思路也是一样。就是从三大差异入手,分别是语法差异、组件库差异和API差异。对语法差异来说,鸿蒙语法有点类似小程序的语法,因此也需要在鸿蒙端模拟实现Web的环境,包括刚才提到的DOM、BOM、API。

对组件库和API库来说,鸿蒙的组件和小程序规范有不少差异,因此需要使用鸿蒙原生的组件和 API去实现刚才提到的标准规范。

最后,放一个Taro框架整体的架构图。

从上往下看,首先我们的语法是支持任何Web端传统的开发框架,包括React、Vue、jQuery等等,我们的标准分别是Web端的渲染规范、小程序标准的组件库、小程序标准的API库。

我们的编译系统选择了前端开发者非常熟悉的Webpack进行编译,运行时,对各个不同的平台,我们会针对标准缺失的部分进行补全,例如在小程序端需要补全一个Web端的渲染环境。但是,在浏览器端甚至React Native端,则需要补全小程序标准的组件库和API库,最终Taro就可以运行在各个平台上。

四、展望未来

以上是对Taro的介绍。下面对未来进行展望。

首先我们W3C小程序标准组已经制定了三个标准,相信随着这些标准的落地,有助于降低普通开发者跨平台适配成本,以及跨平台框架开发者的适配成本。

接下来介绍的是Taro未来的开发计划。目前我们正在做的事情是开发一个和刚才提到Webpack编译类似的基于Vite的编译系统,我们打算支持使用Vite编译小程序端和Web端。未来我们也会探索Flutter的支持。

最后,简单介绍一下Taro社区目前的现状和构成。

我们有个技术委员会,对Taro框架各个方向都有对应工作组,我们参考了业界优秀的开源项目,设计了开发者的荣誉等级制度。因此,我们也非常欢迎大家关注Taro的发展和参与Taro的共建。

以上就是今天我的分享,谢谢大家!

安勍:感谢Taro的同事。现场和线上有没有什么Q&A?

提问:现在我们也在用Taro3,首先在Taro3的架构设计理念非常好,我们用的时候也是基于Taro做了一个插件,希望把Vue生态的组件资产能够迁移到小程序端。我用的时候发现发现Taro对Vue的支持度还是非常高,我们迁移过去也很顺利。

但是,在性能方面,比原生差距有点大,所以想问一下你们从框架本身来说,后面有性能方面优化的规划或者是计划吗?

我看官方文档上有一些从开发者层面,比如长列表有一些优化的建议。我想问一下从框架本身,有没有一些性能优化的规划?

陈嘉健:有的。因为我们在3.5版本也就是上一个版本尝试做了一些性能优化的事情。发现现在优化的瓶颈主要在 template 的渲染上,可能它的渲染方式不是很好,我们也在进一步思考怎么做。

下一步是希望针对长列表环境,就不用运行时渲染的方式,我们会单独针对长列表的组件,使用编译的方式,就是Taro1和Taro2的方式,提前把模板编译出来。

但是,这时候对开发者的语法会有一些限制。初步的想法是这样。

提问:如果这个方案优化的话,对Taro的长列表可能有一些限制

陈嘉健:对。因为在开发自由度和性能上,目前还不能做到两者都兼顾。

因为Taro3模板渲染的方式,会受限于小程序本身的性能,只能用另一个场景,就是编译时的方案提升它的性能。

据我了解,在微信小程序上,它们最近推出了Sky line(音)的渲染系统,帮助他们渲染,就不再分为逻辑层和渲染层,这种小程序的底层逐步的迭代也有利于运行时空的发展。

当然,我们也会不断的看怎么解决一些性能的问题。

请问你们是使用Vue还是React?

提问:我们是运行Vue。

陈嘉健:Vue的长列表还没有做完,相对React性能会稍微差一下。

提问:就是说React的长列表已经优化完了?

陈嘉健:对。React有长列表的组件,Vue还没有。

提问:但你们的长列表组件也是一定要基于Taro的框架上,是你们自己提供的一套组件?

陈嘉健:对。

提问:比如是其他的UI框架,UI的组件库长列表也能做一些优化适配吗?

陈嘉健:你说的什么组件?

提问:比如我用的Want?(音)我们用的是Want的H5版本?

陈嘉健:对。但是你是在小程序还是在H5环境里使用?

提问:我们就是用Taro框架用一些Vue的H5组件,我又不想以前的资产切换到Taro上,我还想继续复用H5的组件库。

陈嘉健:它是Want(音)的H5版本,是借助Taro的能力运行在小程序端上?

提问:对。

陈嘉健:那还是长列表的话,会受限于Taro的功能。

提问:刚才你说的是Taro的长列表?

陈嘉健:对。我们会对现在的虚拟组件,推出一个Vue版本。

提问:如果是性能的话,Vue版本,我们可以把单个组件改到你们版本上,只是单个组件,工作量是我们可以接受的。

陈嘉健:Taro的渲染节点少一点,对Taro来说,性能应该可以接受。其他更新的场景主要是使用创建一个自定义组件,去包裹需要更新的部分,解决频繁更新上的问题。

提问:好的。感谢老师的回答!

陈嘉健:谢谢。

安勍:还有其他问题吗?

提问:您好!老师,我是一个大前端组的成员,现在我面临我们的app是用Flutter生态开发的。刚才我听您说还没有对Flutter端进行适配,我想问一下它能不能提供类似于Taro的运行时在原生端进行嵌入,这样虽然它没有Flutter的环境,但它可以通过Flutter和原生嵌入Taro,可以在我们自己的app上允许一个小程序?

陈嘉健:意思是Taro提供一个和Flutter混合的环境,类似这样的SDK嵌入到app里使用吗?

提问:是的。

陈嘉健:这也是我们考虑的点,Flutter适配还没有详细的规划,目前初步的想法是借助Web,运行小程序和H5端。你说的也是考虑的一个点之一。

提问:我还提一个小小的问题。因为我们知道Flutter除了整体的app开发,还是会有一些组件的开发,Taro的框架后续能不能支持单个组件是Taro,而不是整体的app。

陈嘉健:目前我们在小程序、H5有这样的功能,就是单独把Taro的组件编译成一个平台的组件,给原生区,H5就是对应的H5组件, React Native就是React Native。

提问:如果是迁移Flutter的话还没有做?

陈嘉健:这个目前还没有。会和社区一起讨论需要哪些功能,接下来可以GitHub上讨论。

明白你的意思就是要编译一个对应的Flutter组件。了解了,后续可以在GitHub上多沟通。

返回会议总结页面获取其他话题的会议纪要。

若您对上述内容有任何疑问或需进一步协助,请联系:薛富侨 <xfq@w3.org> 或会议主办方 W3C 北航总部 <team-beihang-events@w3.org>。