专栏首页极乐技术社区深入分析小程序主流跨端框架原理(一)

深入分析小程序主流跨端框架原理(一)

我们将从框架的语法这两个维度进行讲解。第一部主讲Vue跨端框架,第二部主讲类 React 跨端框架。

目前,小程序在用户规模及商业化方面都取得了极大的成功。微信、支付宝、百度、字节跳动等平台的小程序日活都超过了3亿。

我们在开发小程序时仍然存在诸多痛点:小程序孱弱简陋的原生开发体验,注定会出现小程序增强型框架,来提升开发者开发体验;各家厂商小程序API碎片化的现状,注定会有多端框架会成为标配,由跨端框架肩负跨平台移植挑战。

正是因为开发者对于提升小程序开发效率有着强烈需求,小跨端框架发展到如今已经百花齐放、百家争鸣: 除了美团的 mpvue 、网易的 megalo 、滴滴的 chameloen 已经趋于稳定,京东的 Taro开始探索 taro next, Hbuilder 的uni-app 产品和生态持续完善,微信新推出了支持H5和微信小程序的 kbone 框架,蚂蚁金服的 remax。

上述的这么多跨端框架纷繁复杂,我们可以从下面两个维度进行分类:

1

小程序跨端框架的分类

1

按语法分类

从框架的语法来说,可以分为下面两类:

  • Vue语法
  • React语法/类React语法

主流的跨端框架基本遵循 React、Vue 语法,这也比较好理解,可以复用现有的技术栈,降低学习成本。

remax

Taro next

Taro 1/2

megalo

mpvue

uni-app

chameloen

语法

react

react

类 react

vue

vue

vue

类 vue

厂家

蚂蚁金服

京东

京东

网易考拉

美团

Hbuilder

滴滴

2

按实现原理分类

从实现原理上,开源社区的跨端框架大致分为下面两类:

  • compile time编译时
  • runtime运行时

compiletime编译时的跨端框架,主要的工作量在编译阶段。他们框架约定了一套自己的DSL ,在编译打包的过程中,利用 babel 工具通过 AST 进行转译,生成符合小程序规则的代码。

这种方式容易出现 BUG ,而且开发限制过多。早期的Taro 1.0 和2.0的版本就是采用的这种方案,下文会有更具体的介绍。

而另外一种runtime 运行时模式, 跨端框架真正的在小程序的逻辑层中运行起来 React 或者是 Vue 的运行时,然后通过适配层,实现自定义渲染器。这种方式比静态编译有天然的优势,所以 Taro 的最新 Next 版本和 Remax 采用的是这种方案。

2

写在小程序跨端原理之前

通过上文我们知道小程序跨端框架目前有很多嘛,各个大厂都会有自己的一套,百花齐放。文章篇幅有限,如果要分别拆开讲清楚他们各家实现的细节,是一件很困难同时很费时间的事情。

所以,下文会尝试梳理一下主流小程序一些共用性的通用实现原理, 尽量会屏蔽忽略掉各家实现一些细枝末节的细节差异,也不会在文章中贴大段的源码分析,而是通过伪代码来代替。

下面,我们会从 Vue 跨端框架React 跨端框架两个大方向,进入到小程序跨端原理的世界,讲解这些跨端框架的核心原理,深入到源码底层去分析,揭开他们神秘的面纱。

3

Vue 跨端框架

当你使用 megalompvue 这些 Vue 跨端框架时,看上去,我们写的是vue 的代码,然后打包编译之后就可以运行在小程序内,是不是很神奇?这些框架背后做了哪些事情呢?

实际上,这些 Vue的跨端框架 核心原理都差不多,都是把 Vue 框架拿过来强行的改了一波,借助了 vue 的能力。比如说,vue 的编译打包流程(也就是vue-loader的能力), vue 的响应式双向绑定、虚拟dom、diff 算法。上面这些东西跨端框架都没有修改,直接哪来用的。

那么哪些部分是这些跨端框架自己新加的东西呢?涉及到 Vue 框架中操作DOM节点的代码

这些跨端框架,把原本Vue框架中原生 javascript 操作 DOM 的方法,替换成小程序平台的 setData()。为什么要这样呢?不着急,下文会有比较详细的讲解。

不着急,慢慢来,我们先从一个最简单的问题开始。

1

从vue到小程序

首先我们来看,一个 vue 的单文件,究竟做了啥,怎么就能跑在小程序里面了?

我们知道,对于微信小程序来说,需要:.wxml.wxss.js.json

(上面是去微信小程序官网截的图)

而对于一个Vue组件来说,一个vue文件有三个部分组成:template, script, style

那么,这些跨端框架把Vue 单文件中的 <template><script><style>这三个部分对应的代码,拆一拆,分别处理编译一下,分到 .wxml.wxss.js.json 这 4 份文件中,如下图所示:

我们分别从<template><script><style>这三个部分来讨论:

  • <style> 部分是最简单的。一般来说,在 h5 环境中的 css 样式,大部分都可以直接挪到 .wxss,需要处理的部分比较少,除了少部分不支持的属性和 小程序的单位转换
  • <template> 转换到 .wxml稍微复杂一点。我们需要把 h5 的标签啊、vue特殊的语法替换成小程序的标签、小程序特殊的语法。替换的工作我们称为 模板替换 ,下文会有一个章节用来介绍。
  • 最难的是<script>.js, 涉及到 vue 的运行时 如何和 小程序的实例通讯的问题,这一部分会用比较多的章节去介绍。

接下来,我们先看模板替换 ,也就是template生成 .wxml文件的过程。

<template>.wxml

Vue 是采用 template 语法的,各大厂商的小程序也是采用了 template语法。从Vue的 template 转变成小程序的 template 相对比较简单,React的jsx 转变为小程序的 template 就相对比较棘手啦。

Vue 的 template 与小程序的 template 大体是上的语法很类似,但是还是有不一样的地方。例如小程序里没有 <div> 标签,而是小程序厂商提供的 <view> 标签等等

因此我们需要把 Vue 模版转换为微信小程序的 .wxml

例如上图所示,<div> 标签需要转换成 <view> 标签,一些 vue 中的语法也需要进行转化成对应小程序平台的语法。

再比如说,在 Vue 里面绑定事件常用 @methodName 的语法, 转成小程序模版则需要用 bind,同时用 tap 事件替换 click 事件。

除了这个,还有一些vue的模板语法,也需要转成小程序的模板语法

Vue 和小程序插值表达式则是一样的,采用了双花括号,可以不需要做任何转化

上面展示的这些模板替换,都只是替换为微信小程序的语法。转化为其他小程序平台的语法也是类似的思路,如下图所示:

那么,模板的转化具体是如何实现的呢?我们的第一想法是通过正则来匹配,但是要写出匹配出所有情况的正则是非常困难的。

实际上,mpvuemegalouni-app 的框架是采用了 ast 来解析转化模板的。

模板替换过程其实就是两侧对齐语法的过程,把语法不一致的地方改成一样的,是一个 case by case 的过程,只要匹配到不同情况下语法即可,比较费功夫但是难度系数不是很高。

接下来我们看如何把 <script> 中的内容,挪到小程序 .js 中呢?

<script> .js

我们在 .vue 单文件中的 script 部分中, 通常会写下面的代码,我们会写一个 Vue 的配置项对象传入到 Vue 构造函数中,然后 new Vue() 会实例化出来一个 vue 实例。

上面的代码是完全可以跑在小程序的逻辑层里面的,只要引入vue 即可,毕竟 Vue 大部分就是纯粹的 javascript。也就是说,小程序的渲染层里面是完全可以直接运行起来 Vue 的运行时和 React 的运行时的。

但是这样还不够,小程序平台还规定,要在小程序页面中调用 Page() 方法生成一个 page 实例, Page() 方法是小程序官方提供的 API。

在一个小程序的页面中,是必须有 Page() 方法的。微信小程序会在进入一个页面时,扫描该页面中的 .js 文件,如果没有调用 Page() 这个方法,页面会报错。

如下图所示,我们在 <script> 中写的是 new Vue() 这样子的代码,而微信想要的是 Page()

那么,应该怎么解决呢?

Vue 跨端框架他们拓展了 Vue 的框架,把 Vue2.0 的源码直接拷贝过来,改了里面的初始化方法,在初始化方法中调用了 Page() 方法, 如下面伪代码所示:

在 vue 实例化的时候,会调用 init 方法,在 init 方法里面会调用 Page() 函数,生成一个小程序的 page 实例。

这样,我们在一个小程序页面中,就会同时存在一个 vue 的实例,和一个小程序的 page 实例,他们是如何融合起来一起工作的呢?他们之间是如何做到数据管理的?如何进行通讯的呢?

接下来就涉及到 Vue 框架的核心流程了,为了方便一些不了解 Vue 同学,同时也为了更好的深入理解下面讲的内容,接下来会稍微讲一丢丢 vue 的核心流程。(真的只有一丢丢)

Vue 的核心流程

如下图左侧所示,简单来说, 一个 .vue 的单文件由三部分构成: template, script, style

我们先看上图中的橙黄色的路径,也就是 template 部分的处理过程。

如下图所示,template 模板部分会在编译打包的过程中,被 vue-loader 调用 compile 方法通过词法分析生成一个 ast 对象,然后调用代码生成器,经过遍历 AST 树递归的拼接字符串操作,最终生成一段 render 函数, render函数最后会存在打包生成的dist 文件中。

可以看下面这个例子,一段简单的 template 模板如下所示:

经过编译之后,通过 ast 进行分析,生成的 render 函数如下:

render 函数会在第一次 mount时,或者Vue 维护的 data 有更新产生的时候会被执行。

那么执行下面这段 render 函数会拿到什么呢?

上面图中蓝色圆圈中的 _c 方法是创建元素类型的vnode, 而 _v 方法是创建 文本类型的vnode。

Render 函数中会调用这些方法创建不同类型的vnode,最终的产物是生成好的虚拟DOM树 vnode tree,对应上面图中 render 函数的下一个阶段 vnode。

虚拟DOM树是对真实DOM树的抽象,树中的节点被称作 vnodevnode 有一个特点, 它保存了这个DOM节点用到了哪些数据 ,这一点非常重要。

Vue拿到 虚拟dom树之后,就可以去和上次老的虚拟dom树patch diff 对比。

这一步的目的是找出,我们应该怎么样改动现存的老的DOM树,代价才最小。

patch 阶段之后,如果是运行在浏览器环境中, vue 实例就会使用真实的原生 javascript 操作DOM的方法(比如说 insertBefore , appendChild 之类的),去操作DOM节点,更新浏览器页面的视图。

接下来,我们再来看一下上面图中,蓝色的线条的路径。

在new Vue 的时候,Vue 在初始化的时候会对数据 data 做响应式的处理,当有数据发生更新时,最后会调用上文的 render 函数,生成最新的虚拟DOM树。

接着对比老的虚拟DOM 树进行 patch, 找出最小修改代价的vnode 节点进行修改。

上面介绍的流程就是 vue 的整体流程啦。

我们要关心的是,下面的类 vue 小程序跨端框架的核心流程。接下来一起来看吧。

类 vue 小程序跨端框架的核心流程

在进一步讲解之前,我们先思考一个问题。上图中,Vue 在 diff 之后就是操作了原生的 DOM 元素,但是各家厂商的小程序不支持原生DOM操作,因此也就没有修改视图节点的能力。那么我们怎么样才能更新小程序的视图呢?

下面这张图代表了类 vue小程序跨端框架的核心流程图。

咋一看这张图,会发现和上面Vue的图是很像的。毕竟 megalompvue 等小程序框架,本质都是对 vue 的拓展(copy过来改了改)

仔细和上面的 vue 的核心流程图一对比,我们发现,小程序跨端框架的流程图替换掉 vue 原本的 DOM 操作,替换为新增的绿色的setData 操作, 同时还多了一个绿色框框中的的 Page() 方法。

Page() 方法上文有介绍过原因

setData() 是小程序官方提供的 API,用来修改小程序 page 实例上的数据,从而会更新小程序的视图。

『替换掉 vue 原本的 DOM 操作』这一个点比较容易理解,因为小程序容器并没有提供操作小程序节点的 API 方法,这是因为小程序隔离了渲染进程 (渲染层)和逻辑进程 (逻辑层),如下图所示:

在小程序容器中,逻辑层到渲染层的更新,只能通过 setData() 来实现。

不管是 mpvuemegalo ,还是uniapp,这些类 vue 跨端框架,都是通过这种方法来更新视图的。而且,在未来可预见的几年里,只要小程序厂商不提供修改小程序节点的 API 方法,小程序跨端框架更新 DOM 节点仍然会通过 setData 这种 API

好了,到了这一步,我们已经知道了,跨端框架替换了 Vue 框架中 JS 操作DOM 原生节点的 API setData() 来更新小程序的页面。

但是我们还是不知道具体背后做了什么,接下来,看一个具体的例子:

在上面的例子中,showToggle 这个变量代表的数据是维护在Vue 实例上的。

在页面初始化的时候,我们的小程序跨端框架就开始执行了,它会先实例化一个Vue 实例,然后调用小程序官方的 Page() API 生成了小程序的page 实例,并在在 Vue 的 mounted 中会把数据同步到小程序的 page 实例上。

因此在实际页面打开之后,会同时存在小程序原生的Page 实例和 Vue 实例。vue 实例上有数据(我们的 data 本来就是定义在 vue 里面的),小程序Page 实例上也有数据(小程序实例上没数据没法渲染页面对吧)。

当 Vue 中的数据发生变化时,会触发 Vue 响应式的逻辑,走 上图中Vue 更新的那一套逻辑:重新执行 render 函数得出一份最新的 Vnode 树。

接下来 Vue去 diff 新旧两个 Vnode 的树,找出修改 DOM 节点最高效的操作。注意!接下来不是调用操作 DOM 的 API, 而是调用小程序的 setData() API 方法, 修改小程序实例上的对应的数据, 从而让小程序渲染层层去更新视图。

这一套流程下来我们发现,通俗来讲,数据是归 Vue 管。Vue 是一个双向数据绑定的框架,小程序也是一个双向数据绑定的东西,这两个东西放一块,通过跨端框架的运行时来做中间桥接,把数据同步到小程序中。

事件归到小程序容器管,小程序触发各种事件,比如说滚动,事件点击,小程序容器捕获到事件后,会去调用在 Vue 注册的对应的事件处理函数。

上面介绍的模型,是一个通用的Vue 小程序跨端框架的实现。Vue 的小程序跨端框架基本上思路是一致的。有了这些理解和认识,我们再来看一下各家小程序框架是如何实现的:

Mpvue 模型

下面是 mpvue 官方网站上的一张原理图:

从右到左来看,当 Vue 上数据变化时,会通过 mpVue 运行时来通知小程序的实例,从而更新小程序 page 视图。从左到右,当小程序的渲染层容器触发了事件后,会通过跨端框架运行时来找到注册的 vue 的事件回调函数

Uni-app 模型

我们接着来看,下面是 uni-app 的官网的原理图,和上面的图像素级别的相似啊

从右到左来看,当 Vue 上数据变化时,会通过uni-app运行时来通知小程序的实例,从而更新小程序 page 视图。从左到右,当小程序的渲染层容器触发了事件后,会通过跨端框架运行时来找到注册的 vue 的事件回调函数

Megalo 模型

下面是 megao 官方的一张原理图,这两张图和上面看似长的不一样,但表达的的意思是一样的。

小结

在这个小节中,重点部分有跨端框架模板替换、 vue 的核心流程、跨端框架替换了 Vue 的 javascript 操作真实 DOM 的 API 等。

至此,一个 vue 跨端框架的核心流程就已经走完了。这个流程中,一些跨端框架会进行优化,不同的跨端框架会采用不同的优化策略。第二部分我们将探讨【类React跨端框架】,将于下周推送,敬请关注。

本文分享自微信公众号 - 极乐技术社区(wxapp-union),作者:小程序社区

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-10-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【2万字长文】深入浅出主流的几款小程序跨端框架原理

    https://juejin.im/post/6881597846307635214

    桃翁
  • 想跨端开发小程序?这个最流行的跨端框架一定要学习!

    从最早发布的微信小程序,到后来的支付宝小程序、字节跳动小程序、百度小程序、QQ小程序,还有最近发布的360小程序,面对这么多套的代码,开发者该如何开发呢?

    极乐君
  • 如何深入分析小程序运行原理?

    小程序凭借其高曝光率、开发成本低、运行更流畅等优势和特点,一经推出就被广泛使用,面对小程序的火爆,自然而然地,就有很多开发者转战小程序领域,本文主要带大家了解下...

    小风以北
  • 小程序框架选型必看:Taro vs uni-app选型经历!

    公司新产品要求发布到各家小程序,最近研究对比了社区主流的几家小程序开发框架,独坑不如拉人众坑,分享给各位,欢迎和我一起入坑:)

    极乐君
  • 解密腾讯前端技术体系

    为了了解当前前端的发展趋势,让我们从国内各大互联网大厂开始,了解他们的最新动态和未来规划。这是解密大厂前端技术体系的第三篇,前两篇已经讲述了阿里和百度在前端技术...

    前端迷
  • 跨平台解决方案的技术分析

    近 20 年是中国互联网蓬勃发展的时代,以 2010 年为界限,前 10 年是 PC 互联网时代,PC 互联网时代培养了国民上网冲浪的用户习惯,为后 10 多年...

    winty
  • 最新前沿:2019 年大前端技术趋势分析

    一晃眼 2019 年已过大半,年初信誓旦旦要学习新技能的小伙伴们立的 flag 都完成的怎样了?2019 年对于大前端技术领域而言变化不算太大,目前三大技术框架...

    用户4962466
  • IMWebConf 2018 圆满落幕,精彩内容回顾

    2018年10月14日,第七届IMWebConf前端大会在深圳科兴国际会议中心成功举办。今年大会现场参会人员近500人,线上直播参与人数累积近千人。 IMWe...

    腾讯NEXT学位
  • JavaWeb类

    本书全面介绍了Tomcat的架构、各组件的实现方案以及使用方式。包括Tomcat的基础组件架构以及工作原理,Tomcat各组件的实现方案、使用方式以及详细配置说...

    用户5224393
  • 最火移动端跨平台方案盘点

    跨平台一直是老生常谈的话题,cordova、ionic、react-native、weex、kotlin-native、flutter等跨平台框架的百花齐放,颇...

    JackJiang
  • 给1-3年的前端 6 点诚心建议

    最近接触了很多前端的小伙伴,和他们谈了很多职业发展的问题。他们大部分是做了一到三年的前端新手。

    闰土大叔
  • 小程序的当下和未来可能 | 崔红保在GMTC 深圳站演讲内容整理

    简要介绍今天的分享大纲,罗马不是一天建成的,小程序也不是一天发明的;小程序这种介于H5和Native App之间的特殊应用形态,从探索到成熟,经历了哪些过程,我...

    CHB
  • 微信团队分享:微信支付代码重构带来的移动端软件架构上的思考

    本文原文由微信客户端高级工程师方秋枋原创发表于WeMobileDev公众号,收录时有修订和加工,感谢作者的无私分享。

    JackJiang
  • 美团民宿跨端复用框架设计与实践

    从 PC 时代、移动时代到万物互联的 IoT 时代,伴随终端设备的日趋多样化,跨端复用的种子自此落地,开始生根发芽。从依靠容器能力、各类离线化预装包的 Hybr...

    前端森林
  • Thrift RPC 框架分析

    工作中用到Thrift,一直想深入研究一下。今天这篇博客以提问的方式,分析Thrift的源码。文章部分参考自:Thrift源码分析。

    Yano_nankai
  • 最火移动端跨平台方案盘点:React Native、weex、Flutter

    跨平台一直是老生常谈的话题,cordova、ionic、react-native、weex、kotlin-native、flutter等跨平台框架的百花齐放,颇...

    JackJiang
  • .NET平台下的跨平台探索

    三年之前投稿的azure云服务使用经验,记录一下,如今的微软和Azure已不是过去的微软和Azure了

    needrunning
  • 当我们聊“跨端”,聊“框架”时究竟在聊什么

    正式讨论「跨端开发」这个概念前,我们可以先思考一个问题:对大部分前端工作来说,前端主要干些啥?

    公众号@魔术师卡颂
  • React的时间简史

    首先,失踪人口正式回归,近来遇到些事情导致原定的系列计划搁置,深表抱歉,后续会正常迭代。

    Cookieboty

扫码关注云+社区

领取腾讯云代金券