大家好,我叫李伟涛,来自凹凸实验室。今天跟大家分享的主题是用 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 的微信小程序端组件化采用的是小程序 标签来实现的,利用小程序
标签的特性,将组件 JS 文件编译成 JS + WXML 模板,在父组件(页面)的模板中通过
标签引用子组件的 WXML 模板来进行拼接,从而达到组件化的目的。 实践证明,Template 模板方案是一个失败的组件化方案,Taro 开源初期的 Bug 主要来源于此。因为这一方案将 JS 逻辑与模板拆分开了,需要手工来保证 JS 与模板中数据一致,这样在循环组件渲染、组件多重嵌套的情况下,要保证组件正确渲染与 props 正确传递的难度非常大,实现的成本也非常高。而且,囿于小程序
标签的缺陷,一些功能(例如自定义组件包含子元素,等)无法实现。
所以,在经过艰辛的探索与实践之后,我们采用了小程序原生组件化来作为 Taro 的小程序端组件化方案,并且通过一些处理,绕开了小程序组件化的诸多限制,为 Taro 的稳定性打下了坚实基础,并带来了以下好处:
- 小程序端组件化更加健壮
- 尽可能减少由于框架带来的性能问题
- 依托官方组件化,方便以后解锁更多可能
其中有个重要的改进,小程序端性能的优化
最初的版本中,仅仅是对小程序 setData 做了一次异步封装,最终调用 setData 更新的时候还是传入了完整数据。
之前我们讲到过在频繁的调用 setData 和 数据量非常大的时候,小程序就会变得异常卡顿,性能很差。
Taro 在框架级别帮助开发者进行了优化,在 setData 之前进行了一次数据 Diff,找到数据的最小更新路径,然后再使用此路径来进行更新
除此之外,我们还做了更多
- 使用小程序第三方框架
- 与原生小程序进行混写
- 更加健全的 TypeScript 支持
第四部分:开源探索
从 开源 到现在,Taro 一共经历了 1800 余次提交,平均每天近 20 次,最多的一天达 30 次。每一次提交都是进步,每一次提交都让 Taro 更加强大。经过这么多次迭代之后,已经让 Taro 获得重生,尤其是小程序组件化重构完成之后,Taro 从旧版架构的泥潭中一跃而出,成为更加健壮的开发框架。 在我们自己不断反思、优化的同时,也积极融入开源社区,依托社区的力量去建设 Taro。 Taro 到目前为止,一共收到了 500 余个 ISSUES,已关闭近 400 个,正是因为这些 ISSUES ,让我们不断意识到 Taro 的不足,让我们知道如何去进行迭代。 同时,我们也一直鼓励社区的开发者积极提 PR,一个优秀的开源项目需要依靠整个社区的力量才能完善起来,到目前为止,一共收到了 120 余个 PR,已几近全部合入,这些 PR 为 Taro 注入了许多新鲜血液,让 Taro 更加健壮,我们也期望能有更多的开发者可以加入进来,一起来让 Taro 更加美好。 在 GitHub 上交流之余,我们也为开发者们开通了官方微信群供大家一起讨论 Taro 与技术,目前已有超过 1700 位开发者在关注、使用 Taro ,期待更多开发者的加入。
在开源期间,随着 Taro 的逐步完善,越来越多的开发者加入到 Taro 的使用、开发中,产生了更多更优秀的使用案例。
Taro 的发展离不开广大开源爱好者的帮助,在此特别鸣谢广大 Taro 的使用者以及 Taro 主要贡献者
第五部分:面向未来
Taro 将会继续保持迭代,目前已经规划了如下重要功能:
便捷测试
在编译时与运行时提供代码诊断的功能,分析代码优劣,判定代码写法是否规范,以便帮助开发者规避一些由于写法带来的问题。 同时将提供一套测试方案,方便开发者书写并运行组件测试用例,提升代码质量。
多端同步调试
目前 Taro 只能一次调试一个端,这对于开发多端应用来说效率略低,所以,计划提供微信小程序/ H5 / React Native 端同时调试的功能,可以一键启动多端同时编译,从而获得多端同步预览。
微信小程序/H5 代码转 Taro 代码
目前已支持 Taro 代码到小程序代码、 H5 代码的转换,在未来,将提供逆向转换功能,帮助开发者将原本就存在的小程序/H5 项目直接转换成 Taro 项目,从而让原本只能运行在一端的项目获得多端运行的能力,降低开发者的重构成本。
与 React 新特性保持同步
Taro 是遵循 React 语法规范的,但是 React 一直在迭代在变化,Taro 作为 React 的追随者也将会保持与 React 新特性同步,让 Taro 最大程度接近 React 开发体验。
快应用端支持
目前 Taro 已经完成了快应用端组件库与 API 的适配,快应用端的文件转换与模板转换也正在开发中,不久的将来就会发布支持快应用端转换的版本。 支付宝小程序与百度智能小程序支持 已预研支付宝小程序与百度智能小程序转换的可行性,即将进入开发。
多端可视化拖拽搭建
目前 Taro 是依靠开发者手工编写代码来获得多端应用的,Taro 未来计划提供一个多端可视化拖拽搭建的功能,可以通过拖拽组件的方式来生成多端应用。 同时,Taro 将联合各大公司小程序开发团队,推出丰富的行业模板,为各行业应用可视化搭建提供完整的解决方案。
完善生态
在开源之初,Taro 一直处于封闭的状态,没有适配的 UI 库,也无法使用第三方组件库,而这些对开发效率的桎梏非常严重,社区内对此反馈较多。所以,我们基于 Taro 推出了首个可以跨多端使用的多端 UI 库 Taro UI,目前已经支持了微信小程序与 H5 端,不久之后将完成 React Native 端的适配,可以同步提供给 React Native 端使用。
最后,多端统一开发框架 Taro 1.0 正式发布!
- 更加健壮的组件化
- 支持引用小程序第三方组件库
- 与原生小程序代码混写
- 极致的性能优化
- 更加丰富的 JSX 语法支持
- 全面支持 TypeScript
- React Native 转换支持
- ……