跨端跨栈连载 6/7:在物联网多设备屏 AIoT 中实践跨端方案

6,931 阅读15分钟

前端早早聊大会,前端成长的新起点,与掘金联合举办。 加微信 codingdreamer 进大会专属内推群,赢在新的起跑线。


第十四届|前端成长晋升专场,8-29 即将直播,9 位讲师(蚂蚁金服/税友等),点我上车👉 (报名地址):


正文如下

本文是第九届跨端跨栈 - 前端早早聊第 68 场,来自天猫精灵 IOT 前端团队的 别针 分享讲稿简要整理版(完整版含演示请看录播视频和 PPT):


一、个人简介

  • 大家好,我是来自天猫精灵 IOT 前端团队的 别针,很荣幸今天有机会跟大家分享我们在物联网领域的一些跨端开发的实践经验,我是 2010 年开始从事前端开发的工作,先后在携程、点评、艺龙等公司呆过,17年底加入阿里,一直从事 IOT 前端方面的工作

二、目录

三、跨端场景和特点

1.跨端场景

  • 提到物联网,大家可能首先会想到各种各样的设备,我们的跨端场景就是需要跑在各种各样的设备上,所以这个跟之前大家分享的,主要是在手机端可能会有一些差异。

1.1 端(物联网设备):手机、音箱、电视、手表和车机…

1.2 系统:IOS、Android、Linux、RTOS…

1.3 技术栈:ReactNative、H5、cube小程序

  • 可能 cube 这个东西大家会比较陌生,在物联网场景下相当于是小程序与 rn 的一个结合,它相当于是开发的时候,DSL 是小程序,但是渲染的时候是通过 cube 去做视图的渲染,把我们的跨端场景总结下来,有这么一些特点,碎片化特别严重,我们涉及到的端、屏、技术栈非常多,而且还在持续增长。

2.跨端特点

  • 我们应用特点就是强交互、功能种类多、设备多的特点,它的业务场景是不一样的,我们在不同设备领域去做技术沉淀周期比较长,所以我们需要对我们的应用,从一个比较长的时间线去看我们应用的发展。

3.应用展示

  • 这边展示的是目前我们线上跑着的一些我们的应用,在其他屏上那些应用暂时还没有对外开放,这里暂时只展示了手机端的一些应用

四、跨端方案和思考

  • 因为碎片化严重,我们主要解决就是怎么提效的问题,不然的话这一块肯定是一个人力投入的黑洞。

1.如何降本提效?

1.1 跨端开发方案:主要解决技术栈碎片的问题

1.2 可视化搭建:主要解决平碎片功能以及UI碎片的问题

2.跨端的实现方式有哪些?

2.1 代码编译

  • 目前业界比较流行,大多数框架所采用的一种方式
  • 实现原理:将一种 DSL 通过编译的方式编译成各个平台的 DSL ,然后结合一些运行时的一些支撑框架,然后实现跨端。

2.2 跨平台解析器

  • 是定义一套 DSL,然后在各个操作系统上实现这种 DSL 的一个解析引擎,以实现跨端。最出名的比如说web以及flutter

2.3 云端渲染用户端展示

  • 在云端进行渲染,客户端只是作为展示,借着网速的提升,以及云时代跟无机时代的到来,采用的一种方案,目前业界主要在一些手机游戏上有过一些相关的实践。

3.百分百的跨端是否可行?

3.1 代码编译方案:

  • 做过代码编译的同学应该都知道,不同语言之间语法能力上本身是不对等的,想要通过编译的方式来达到百分百的跨端,基本上是难度非常高,基本上是不可行的

3.2 跨平台解析器:

  • 如果不考虑性能资源占用和成本的问题,这种方案是很有希望做到百分百实现跨端的。但比较可惜的是除去我们现在标准操作系统之外,其实现在还有一些超级端,这些超级端它承载了一些操作系统的角色,但是里面并没有提供操作系统这样的一个完整的开发能力,比如说现在最流行的小程序,这其实是一种受限环境。在这种受限环境下,这些解解析器可能就是很难去百分百去实现它的能力。

3.3 云端渲染

  • 这种方案理理论上是一种比较完美的扩大方案,因为你运行时是在云端,我们是可以完全采用一样的技术栈,渲染出来之后下发到设备端进行展示,但是受限于目前就是 5g 的普及,以及一些环境因素,现阶段只能进行一些探索和展望。

4.现实一点,我们应该选择哪种跨端方案?

  • 通过刚才的分析,我们选择的是第一种就是代码编译的方式

5.选择哪种 DSL 作为开发态 DSL?

5.1 怎么选择?

  • 根据团队情况,以及你们主要投放的哪些端,以及团队成员的技术背景来去具体分析采用哪种

5.2 我们的选择

  • 我们团队主要的技术站其实是 react 技术栈,我们投放最大的端其实是小程序。天猫精灵 APP 以及天猫精灵音箱里面都集成了支付宝小程序的容器,所以小程序是我们投放的最大的一个端。为了共享小程序的生态,同时我们对三方去开放的一个开发体系,也是小程序的开发体系
  • 我们的方案: react 以及小程序的双 DSL 开发方式

6.如何实现跨端的最大化复用?

7.如何摆脱历史包袱,对跨端方案进行持续升级?

  • 当我们要开发的应用,它的生命周期比较长的时候,长过一些技术战的迭代的时候,我们就要考虑怎么使我们的应用能够跟随技术栈的升级去不断的更新我们的技术栈,而不是绑死在一个框架上

8.我们的跨端架构方案

  • 这张图简单展示了我们对模块管理的简单示意,我们开发了一个模块管理的系统,去管理我们源代码,编译出来各个平台上的代码的模块。

五、关键技术点

1.跨端基础组件

基础组件是你开发应用就是视图层不可分割的一个最小的组件,组件基本都是有平台本身提供的。对于基础组件来说,我们主要的工作其实就是抹平各个端各个平台上的基础组件的差异。

1.1 布局组件

  • 常用布局组件:View、Text
  • 我们可以通过编译的方式,去把这大量的不同的布局组件把它编译为 view 跟 text 两种组件,然后结合他们的一些默认样式是实现 html 里面比较丰富的有语义化的一些标签。

1.2 功能组件

  • 常用功能组件:Image、Video、Input、Canvas、Map……
  • 这些组件是每一个组件有一些特殊功能,现在其实对比下来各个平台上提供的这些功能组件都差不多,主要区别在于功能组件的它的名称,它的属性上的一些差异,对于这些组件我们主要做的事情就是去对比各个平台上组件的差异,去对他们进行抹平。

2.跨端模板

2.1 指令模板

  • 指令模板其实就是在类似于 xml 的基础上去定义了一套指令,比如说属性或者标签之类的来实现有限的逻辑能力,比如说简单的表达式,循环判断,小程序其实都属于这类模板

2.2 JS语言混合模板

  • JS 语言混合模板,就是在字符串或者 xml 中使用特殊的字符进行分割,把检索语法混入进去,使模板具有就是检索几乎完整的表达能力,JSX 就属于这类模板

2.3 两个模板比较

  • 单从模板层面来看,语言混合的模板的表达能力肯定是要远远大于指令模板的,但是通过模板与数据结合渲染出的结果上来讲,其实两者的能力是对等的
  • 模板结合数据渲染出的结果,两个模板其实我们可以几乎把它们等同,而指令模板的表达能力,因为要是js语言混合模板的一个子集,其实 js 混合模板就相当于是指令模板,再加上一些额外的 js 逻辑去达成等式
  • 语言混合模板,他去对数据渲染就等同于指令模板,再加上我通过一个额外的 js 逻辑,对于要渲染的数据进行预处理,然后去渲染,要根据这个等式,我们就可以来通过编译的方式对模板进行编译。
  • 因为编译的方式其实是很开放的,对于两种模板的互转的方式,这里介绍一下我们采用的通过提出冒泡的方式,将就是一个语言混合模板,把它分离成一个指令模板以及一个预处理函数,如下图所示
  • 这张图其实就是一个简单的示意,就是我们怎么通过编译的方式,把一个 JSX 的模板编译成一个指令模板跟一个预处理函数
  • 为了显示上的简介,我们省略了很多其中的一些中间节点,只把一些关键节点保留下来。babel 在节点树上遍历,其实是通过深度遍历的每个节点,又分为进入和离开两个时机对节节点进行操作。
  • 我们通过冒泡的方式对模板进行分离的时候,会配置我们要编译的目标的指令模板,支持哪些语法,这样的话在进行分离的时候,可以把支持的语法分离成指定模板,不支持语法分离到处理函数里。具体的过程就是我们在根节点的进入的时候,会在根节点的 state 上挂三个栈,一个是作用域栈,一个是支持的语法栈以及不支持的语法栈。
  • 然后下面每个节点,我们在他的退出的时候会去判断,看看当前节点以及它的父节点,他们是不是都是我们所支持的语法,或者他们都是我们不支持的语法。如果就是他跟他的父节点类型是一样的,那么我们就继续遍历。当我们遍历到一个节点发现,比如说当前节点它是我们支持的语法,而它的父节点是我们不支持的语法,或者就是他的当前节点是我们不支持语法,他的父节点是我们支持的语法的时候,我们就会把当前这个节点push到对应的一个刚才我们根节点创建的栈上,从另外一个栈上再弹出我们父节点同类的节点挂载到父节点上,依次进行冒泡。这样的话我们通过这种冒泡的方式,一直遍历完之后,我们就把整个节点树分离成了一棵树是我们指定模板所支持的语法节点树,一颗树是我们不支持的语法节点树,不支持的语法节点树其实就是我们分离出来的数据与处理函数。
  • 这里介绍的只是核心的处理过程,其中还有更多其他的细节操作,比如说本身不同的指令,模板语法具体的语法细节是不一样的。就像刚才 uni-app 他们介绍的时候,其实也对比了不同的模板语法里面的一些差异,其实里面对于支持的语法节点也还要进行一次转换。

3.跨端样式

3.1 基本样式能力对齐

  • 比如说小程序或者 h5 里面,同样的样式表,上面的样式的语法可能会名称之类的,会有一些差异。

3.2 基本样式能力补齐

  • 不同的平台上,可能某些样式有缺失,但是我们可以通过比如说原生能力或者 js 能力或者其他默认样式的转换来能够补齐这方面的能力

3.3 样式继承、选择器等高级功能

  • 我们所采用的方式是基本能力对其以及样式补齐上的一部分,然后我们没有选择样式这一块继续使用继承跟选择器的功能
  • 之前我们在RN里面有实践过,让样式去支持类似样式继承、选择器这样的能力,但是因为这样的方式会造成组件节点上的 style 会数量暴增,并且没法通过 StyleSheet 方式对于这种数据传递做压缩,所以造成本身通道数据传输量暴增性能会有明显的下降,所以我们放弃了这种,在我们这里我们主要就是对于基本的样式进行了抹平,然后采用非选择性非继承的方式来处理样式,

4.跨端组件模型

4.1 生命周期

4.2 数据到视图的渲染方式

4.3 视图事件的监听方式

4.4 组件引用方式

  • 这一块的话主要就是在以下生命周期,数据到视图的渲染,事件监听、组件引用等几个方面各个平台上有差异。这一块刚才宝哥介绍 uni-app 的时候也有一些介绍,这里面其实就是一些细节的处理,这一块涉及编译的不多,是为了支撑运行时能够抹平做的一些简单的提取编译,然后大部分功能其实都是在运行时去实现的,这一块就不做详细介绍。目前一些开源的跨端框架,其实这一块其实都有实现,如果有兴趣的同学可以找一些开源框架去看一下这一块的实现。

5.跨端应用模型

  • 应用模型也比较类似,只不过是要抹平的点有些差异。因为我们之前重点介绍了,其实我们为了不强制捆绑在一种框架上,让我们的应用能够随着我们的发展,能够持续跟随技术的迭代,所以我们的不同的模块可能采用的不同的技术方案去实现跨端

6.源代码组织方式

6.1 中小型项目

  • 对于中小型项目的话,其实可以使用 yarn workspace 或者 lerna 进行这种代码管理,它其实都是在同一个代码仓库里,通过文件夹的方式去划分不同的模块,每个模块其实可以有自己的脚手架、有自己的文件依赖,就是可以发布独立的 npm 包,把所有的模块放在一个个的仓库,对于中小型项目这种方式其实可以足够管理

6.2 大型项目

  • 特点:后面的人模块数量增长的会非常大,以及它的时间会延续的比较长
  • 组织方式:采取类似于 git group 的方式进行管理,就是每个模块是一个独立的 git 仓库。

六、总结

1.没有好的方案,只有最适合的方案

  • 要根据我们的业务场景,各个方面的特点来考虑
  • 比如说你要跨哪些端,这个就要考虑到这些端的技术栈有哪些?然后按照技术栈进行各个划分,看怎么样去抹平,然后以哪个端为主,首先要保证端上的体验,其实这个就会影响到你选用哪种 DSL 作为开发态的 DSL 你的一些技术倾向可能都要往端上去,有一些倾斜,还有你的各端的能力是否完全一致,其实就涉及到你的整套方案是写一次到处运行还是学习一次,到处去用相同的方式去开发,以及根据你的项目团队的一些背景特点,选择不同的技术方案。

七、团队介绍

1.招聘要求

1.1 职责

  • 天猫精灵 APP 前端部分、天猫精灵小程序
  • 天猫生活物联网平台的搭建。
  • 天猫精灵音箱、手表、电视、车机等这些设备中的 IOT 部分前端工作

1.2 现有技术方向

  • 多端多屏技术
  • 可视化搭建
  • 微前端
  • AIOT 人机互动

1.3 招聘职位

  • 高级前端工程师
  • 前端技术专家

2.加入我们

3.结束语


本文使用 mdnice 排版