用 React 开发小程序的探索之路 (演讲内容整理)| 掘金开发者大会

大家好,我叫李伟涛,来自凹凸实验室。今天跟大家分享的主题是用 React 开发小程序的探索之路 。

在目前市面上已经有非常多的小程序开发框架,其中的佼佼者如 wepy 以及 mpvue ,他们都是非常优秀的小程序开发框架。但是它们都有一个共同的特点,都是通过类 vue 语法的小程序开发框架。这点对于国内一些 react 的开发者来说就显得有点遗憾了。

我们团队在去年就整体转入了 react 开发阵营,对于我们团队来说, react 会更加熟悉一些。所以我们一直在探索如何用 react 开发小程序,前端时间我们开源了一个框架,叫做 Taro 。本次也会围绕这个,来分享 探索使用 react 开发小程序。主要包含以下五个部分内容:

第一部分:原生开发之痛

开发小程序由三部分组成,这三大部分都是由四种类型文件,如下图所示:

我们以 JS 文件为例:

我们在写原生小程序的时候,这两份代码是非常常见的。 它们都是借助函数工厂类的方式去构建页面以及组件。 在小程序中的一大特色就是使用字符串模板的形式来编写界面,如图:

以上就是一些小程序官方写法上的一些约定,但也是这些约定,让开发者存在一些开发上的痛点,这些痛点主要集中在:

  • 开发体验
  • 性能瓶颈

在开发体验上,代码组织稍显复杂。 当组件和页面越来越多,项目越来越庞大的时候开发成本就会显得有点高,其次就是编码体验不够顺畅,如下图:

页面或者组件无法被继承的时候,我们在实现一些功能的时候会受到一些限制 ,同时小程序本身提供了一些 API ,但是却没有提供一个跟编辑器很好结合的东西,当我们在使用这些 API 的时候缺乏智能提示。 其次就是字符串模板稍显孱弱。例如 :

当我们实现一个日期格式化的时候,点击的时候无法传参,还有就是直接写一个格式化函数是无法运行的,我们需要借助 wxs 这样的一些工具去实现这样的一个功能,但是这样是非常麻烦的。 还有就是小程序的代码规范并不是很统一,以 Button 组件为例:

一些属性参数都是有很大的差异的。 其次就是缺乏统一的自动化编译处理,导致无法直接在小程序中直接使用一些 新的 ES 语法,以及 SASS 、 LESS 来书写样式代码。

在性能瓶颈上面,小程序的整体架构是这样的:

分为视图层和逻辑层,这两个层之间是有一个特定的通信方式的,当我们在调用 setData 去更新视图的时候,小程序首先把你传入的数据 使用 JSON.stringify 进行序列化,之后拼接成一段可执行的 JS 脚本,最后运行。在这样的一层通信机制上,导致去调用 setData 的去更新视图的时候成本非常之高。所以小程序官方也是提供了一些对于性能优化上的提示

  • 避免频繁 setData
  • setData 避免传入大规模数据

针对以上的痛点和限制,业界也有一些优秀的解决方案,诸如 mpvue, wepy, 但是它们都是类 vue 的开发框架。正如前面所说,这样子的话对于我们团队或者使用 react 的开发者有点遗憾。

第二部分:如何使用 React 开发小程序

使用 react 来开发应用带来的的一些好处:

react 和 小程序是有一些共同特点的

  • View = F(Data),都是通过数据来驱动视图模型
  • 同时都是用一种类似的 API 来驱动整个视图的更新 (小程序:this.setData(), react:this.setState() )

正因为这样,也是更加想用 react 来开发小程序。 经过进一步的研究发现,小程序和 react 之间的差异是非常大的 主要是由于三大块的差异:

JS 代码对比:

生命周期对比:

模板对比:

这么大的差异导致我们想用 react 来开发小程序的难度非常之大,所以我们应该怎么使用 react 来开发小程序呢? 仔细思考一下我们的需求,我们是希望通过 react 语法的代码来开发小程序,那么其中的核心工作就是将 react 代码通过某种转换操作,变成小程序可以运行的代码。这样一种在两种语法之间转换的这种操作其实就涉及到一个编译原理。 编译原理的一个大致过程大概如图所示:

其中最核心的就是把源代码编译成 AST (虚拟语法树),然后将 AST 进行转换操作得出目标代码。 在 JS 中,它是有自己的 AST 规范来进行定义,这个规范就是 ESTree Spac

在 JS 领域中,有非常多的 JS 的解析器,来帮你把代码转换成语法树的工具,其中最广为应用的就是 BABEL。

它提供了一套非常完成的工具来帮你做代码转换。 从源代码到语义分析,我们都可以借助 BABEL 来进行转换。 在这之后的语法树转换、代码优化还是需要们自己来进行的,这一部分也是非常繁琐且复杂。

在 Taro 中,我们通过在编译时处理以及运行时适配来转换成小程序代码,

编译时的处理:

在 JSX 中,通常有各种各样的写法:

这导致在编译的时候非常复杂,需要做大量的测试用例来保证转换是正常的。

代码编译出来时候,还是不能只在小程序上运行的,小程序需要一个运行时的适配来帮助我们把代码运行在小程序里面。 运行时的框架主要是一些生命周期的转换适配,还有一些事件处理。

仅仅这些是不够的,如果真正需要投入开发使用还是有点差距的。这个时候我么你需要一个开发工具来进行配合。

同时,Taro 来提供了一些贴心的功能,来帮助我们获得良好的开发体验

  • 智能的代码提示
  • 健全的错误代码检查

第三部分:重生之路

开源之初,由于种种原因,Taro 的微信小程序端组件化采用的是小程序