开发者(KaiFaX)
面向全栈工程师的开发者
专注于前端、Java/Python/Go/PHP的技术社区
作者 | 雾豹
来源 | https://juejin.im/post/6881597846307635214
前言
目前,小程序在用户规模及商业化方面都取得了极大的成功。微信、支付宝、百度、字节跳动等平台的小程序日活都超过了3亿。
我们在开发小程序时仍然存在诸多痛点:小程序孱弱简陋的原生开发体验,注定会出现小程序增强型框架,来提升开发者开发体验;各家厂商小程序API碎片化的现状,注定会有多端框架会成为标配,由跨端框架肩负跨平台移植挑战。
正是因为开发者对于提升小程序开发效率有着强烈需求,小跨端框架发展到如今已经百花齐放、百家争鸣:除了美团的 mpvue
、网易的 megalo
、滴滴的 chameloen
已经趋于稳定,京东的 Taro
开始探索 taro next
, Hbuilder 的uni-app
产品和生态持续完善,微信新推出了支持H5和微信小程序的 kbone
框架,蚂蚁金服的 remax
上述的这么多跨端框架纷繁复杂,我们可以从下面两个维度进行分类:
小程序跨端框架的分类
按语法分类
从框架的语法来说,可以分为下面两类:
Vue 语法
React 语法 / 类 React 语法
主流的跨端框架基本遵循 React、Vue 语法,这也比较好理解,可以复用现有的技术栈,降低学习成本。
从实现原理上,开源社区的跨端框架大致分为下面两类:
compile time
编译时
runtime
运行时
compile time
编译时的跨端框架,主要的工作量在编译阶段。他们框架约定了一套自己的 DSL
,在编译打包的过程中,利用 babel 工具通过 AST 进行转译,生成符合小程序规则的代码。
这种方式容易出现 BUG
,而且开发限制过多。早期的 Taro 1.0 和 2.0 的版本就是采用的这种方案,下文会有更具体的介绍。
而另外一种runtime
运行时模式, 跨端框架真正的在小程序的逻辑层中运行起来 React 或者是 Vue 的运行时,然后通过适配层,实现自定义渲染器。这种方式比静态编译有天然的优势,所以 Taro 的最新 Next 版本和 Remax 采用的是这种方案。
写在小程序跨端原理之前
通过上文我们知道小程序跨端框架目前有很多嘛,各个大厂都会有自己的一套,百花齐放。文章篇幅有限,如果要分别拆开讲清楚他们各家实现的细节,是一件很困难同时很费时间的事情。
所以,下文会尝试梳理一下主流小程序一些共用性的通用实现原理, 尽量会屏蔽忽略掉各家实现一些细枝末节的细节差异,也不会在文章中贴大段的源码分析,而是通过伪代码来代替。
下面,我们会从 Vue 跨端框架和 React 跨端框架两个大方向,进入到小程序跨端原理的世界,讲解这些跨端框架的核心原理,深入到源码底层去分析,揭开他们神秘的面纱。
Vue 跨端框架
当你使用 megalo
、mpvue
这些 Vue 跨端框架时,看上去,我们写的是vue
的代码,然后打包编译之后就可以运行在小程序内,是不是很神奇?这些框架背后做了哪些事情呢?
实际上,这些 Vue的跨端框架 核心原理都差不多,都是把 Vue 框架拿过来强行的改了一波,借助了 vue 的能力。比如说,vue 的编译打包流程(也就是vue-loader的能力), vue 的响应式双向绑定、虚拟dom、diff 算法。上面这些东西跨端框架都没有修改,直接哪来用的。
那么哪些部分是这些跨端框架自己新加的东西呢?
涉及到 Vue 框架中操作DOM节点的代码。
这些跨端框架,把原本Vue框架中原生 javascript 操作 DOM 的方法,替换成小程序平台的 setData()
。为什么要这样呢?不着急,下文会有比较详细的讲解。
不着急,慢慢来,我们先从一个最简单的问题开始。
从 vue 到 小程序
首先我们来看,一个 vue
的单文件,究竟做了啥,怎么就能跑在小程序里面了?
我们知道,对于微信小程序来说,需要有 4份文件:.wxml
、.wxss
、.js
、 .json
。
(上面是去微信小程序官网截的图)
而对于一个 Vue 组件来说,一个 vue 文件有三个部分组成:template
, script
, style
。
那么,这些跨端框架把Vue 单文件中的 、
、
这三个部分对应的代码,拆一拆,分别处理编译一下,分到
.wxml
、.wxss
、.js
、 .json
这 4 份文件中,如下图所示:
我们分别从、
、
这三个部分来讨论:
部分是最简单的。一般来说,在 h5 环境中的 css 样式,大部分都可以直接挪到
.wxss
,需要处理的部分比较少,除了少部分不支持的属性和 小程序的单位转换
转换到
.wxml
稍微复杂一点。我们需要把 h5 的标签啊、vue特殊的语法替换成小程序的标签、小程序特殊的语法。替换的工作我们称为 模板替换
,下文会有一个章节用来介绍。
最难的是 到
.js
, 涉及到 vue
的运行时 如何和 小程序的实例通讯的问题,这一部分会用比较多的章节去介绍。
接下来,我们先看模板替换
,也就是template 生成 .wxml
文件的过程。
到 .wxml
Vue 是采用 template
语法的,各大厂商的小程序也是采用了 template
语法。从 Vue 的 template
转变成小程序的 template
相对比较简单,React 的 jsx 转变为小程序的 template 就相对比较棘手啦。
Vue 的 因此我们需要把 Vue 模版转换为微信小程序的 例如上图所示, 再比如说,在 Vue 里面绑定事件常用 除了这个,还有一些vue的模板语法,也需要转成小程序的模板语法 Vue 和小程序插值表达式则是一样的,采用了双花括号,可以不需要做任何转化 上面展示的这些模板替换,都只是替换为微信小程序的语法。转化为其他小程序平台的语法也是类似的思路,如下图所示: 那么,模板的转化具体是如何实现的呢?我们的第一想法是通过正则来匹配,但是要写出匹配出所有情况的正则是非常困难的。 实际上, 模板替换过程其实就是两侧对齐语法的过程,把语法不一致的地方改成一样的,是一个 case by case 的过程,只要匹配到不同情况下语法即可,比较费功夫但是难度系数不是很高。 接下来我们看如何把
template
与小程序的 template
大体是上的语法很类似,但是还是有不一样的地方。例如小程序里没有
标签等等
.wxml
。
标签,一些 vue 中的语法也需要进行转化成对应小程序平台的语法。
@methodName
的语法, 转成小程序模版则需要用 bind
,同时用 tap 事件替换 click 事件。mpvue
、megalo
、uni-app
的框架是采用了 ast
来解析转化模板的。 中的内容,挪到小程序
.js
中呢?