滴滴开源小程序框架Mpx

Mpx是一款致力于提升小程序开发体验的加强型小程序框架,经过Mpx,咱们可以以最早进的web开发体验(Vue + Webpack)来开发生产性能深度优化的小程序,Mpx具备如下一些优秀特性:css

  • 数据响应特性(watch/computed)
  • 加强的模板语法(动态组件/样式绑定/类名绑定/内联事件函数/双向绑定等)
  • 深度性能优化(原生自定义组件/基于依赖收集和数据变化的setData)
  • Webpack编译(npm/循环依赖/Babel/ESLint/css预编译/代码优化等)
  • 单文件组件开发
  • 状态管理(Vuex规范/多实例/可合并)
  • 跨团队合做(packages)
  • 逻辑复用能力(mixins)
  • 脚手架支持
  • 小程序自身规范的彻底支持
  • 支付宝小程序的支持

设计思路

目前业界主流的小程序框架主要有WePY,mpvue和Taro,这三者都是将其余的语法规范转译为小程序语法规范,咱们称其为转译型框架。不一样于上述三者,Mpx是一款基于小程序语法规范的加强型框架,咱们使用Vue中优秀的语法特性加强了小程序,而不是让用户直接使用vue语法来开发小程序,之因此采用这种设计主要是基于以下考虑:前端

  • 转译型框架没法支持源框架的全部语法特性(如Vue模板中的动态特性或React中动态生成的jsx),用户在使用源框架语法进行开发时可能会遇到不可预期的错误,具备不肯定性
  • 小程序自己的技术规范在不断地更新进步,许多新的技术规范在转译型框架中没法支持或须要很高的支持成本,而对于加强型框架来讲只要新的技术规范不与加强特性冲突,就可以直接支持

技术实现

小程序刚推出时不支持自定义组件,没法进行组件化开发,WePY和mpvue作了一系列的工做来支持了这一关键特性,大大提升了用户的开发体验和效率。WePY和mpvue的组件化支持是基于编译作的组件化封装,用户编写的组件模板会被编译为Page中模板的一部分,在组件中定义的数据会被编译为Page中的数据,对组件进行数据更新也会基于路径映射调用Page.setData。这在当时的技术条件下是很棒的技术方案,但该方案在复杂的小程序应用中存在性能问题,缘由在于该方案中页面的数据量会很大,并且每一个组件的局部更新实际上都会成为页面级别的全局更新,在组件较多的页面中产生很大的性能开销。vue

在小程序自定义组件推出后,咱们经过性能测试确认了小程序自定义组件支持组件级别的局部更新,具备良好的更新性能。因为自定义组件在当时是最新的技术标准,业内的小程序框架都未支持,而咱们在业务上又有复杂小程序的开发需求,因而咱们就基于小程序自定义组件启动了Mpx框架的设计与开发。node

Page与Component setData性能对照git

Component Page
局部更新 1975ms 7186ms
全局更新 6210ms 24612ms

性能衡量标准说明:
局部更新:文档中存在1000个节点,其中一个节点更新1000次的耗时;
全局更新:文档中存在5个节点,5个节点独立更新1000次的耗时 以上数据在iPhone7微信小程序环境下测试得出github

数据响应与性能优化

数据响应做为Vue最核心的特性,在咱们的平常开发中被大量使用,可以极大地提升前端开发体验和效率,咱们在框架设计初期最先考虑的就是如何将数据响应特性加入到小程序开发中。在数据响应的实现上,咱们引入了MobX,一个实现了纯粹数据响应能力的知名开源项目。借助MobX和mixins,咱们在小程序组件建立初期创建了一个响应式数据管理系统,该系统观察着小程序组件中的全部数据(data/props/computed)并基于数据的变动驱动视图的渲染(setData)及用户注册的watch回调,实现了Vue中的数据响应编程体验。与此同时,咱们基于MobX封装实现了一个Vuex规范的数据管理store,可以方便地注入组件进行全局数据管理。为了提升跨团队开发的体验,咱们对store添加了多实例可合并的特性,不一样团队维护本身的store,在须要时可以合并他人或者公共的store生成新的store实例,咱们认为这是一种比Vuex中modules更加灵活便捷的跨团队数据管理模式web

做为一个接管了小程序setData的数据响应开发框架,咱们高度重视Mpx的渲染性能,经过小程序官方文档中提到的性能优化建议能够得知,setData对于小程序性能来讲是重中之重,setData优化的方向主要有两个:npm

  1. 尽量减小setData调用的频次
  2. 尽量减小单次setData传输的数据

为了实现以上两个优化方向,咱们作了如下几项工做:编程

  • 将组件的静态模板编译为可执行的render函数,经过render函数收集模板数据依赖,只有当render函数中的依赖数据发生变化时才会触发小程序组件的setData,同时经过一个异步队列确保一个tick中最多只会进行一次setData,这个机制和Vue中的render机制很是相似,大大下降了setData的调用频次;
  • 将模板编译render函数的过程当中,咱们还记录输出了模板中使用的数据路径,在每次须要setData时会根据这些数据路径与上一次的数据进行diff,仅将发生变化的数据经过数据路径的方式进行setData,这样确保了每次setData传输的数据量最低,同时避免了没必要要的setData操做,进一步下降了setData的频次。 基于以上优化,咱们大大减小了小程序setData的调用频次和传递数据量,与第一版Mpx中track全量数据的方案相比提示显著。

Mpx setData优化效果json

旧版Mpx 新版Mpx
setData次数 164 88
setData数据量 370kB 38kB

以上数据由较复杂小程序在固定交互流程后统计得出

Mpx数据响应机制流程示意图
Mpx数据响应机制流程示意图

编译构建

咱们但愿使用目前设计最强大、生态最完善的编译构建工具Webpack来实现小程序的编译构建,让用户获得web开发中先进强大的工程化开发体验。使用过Webpack的同窗都知道,一般来讲Webpack都是将项目中使用到的一系列碎片化模块打包为一个或几个bundle,而小程序所须要的文件结构是很是离散化的,如何调解这二者的矛盾成为了咱们最大的难题。一种很是直观简单的思路在于遍历整个src目录,将其中的每个.mpx文件都做为一个entry加入到Webpack中进行处理,这样作的问题主要有两个:

  1. src目录中用不到的.mpx文件也会被编译输出,最终也会被小程序打包进项目包中,无心义地增长了包体积;
  2. 对于node_modules下的.mpx文件,咱们不认为遍历node_modules是一个好的选择。

最终咱们采用了一种基于依赖分析和动态添加entry的方式来进行实现,用户在Webpack配置中只须要配置一个入口文件app.mpx,loader在解析到json时会解析json中pages域和usingComponents域中声明的路径,经过动态添加entry的方式将这些文件添加到Webpack的构建系统当中(注意这里是添加entry而不是添加依赖,由于只有entry能生成独立的文件,知足小程序的离散化文件结构),并递归执行这个过程,直到整个项目中全部用到的.mpx文件都加入进来,在输出前,咱们借助了CommonsChunkPlugin/SplitChunksPlugin的能力将复用的模块抽取到一个外部的bundle中,确保最终生成的包中不包含重复模块。咱们提供了一个Webpack插件和一个.mpx文件对应的loader来实现上述操做,用户只须要将其添加到Webpack配置中就能够以打包web项目的方式正常打包小程序,没有任何的前置和后置操做,支持Webpack自己的完整生态。

Mpx编译构建机制流程示意图
Mpx编译构建机制流程示意图

现状和将来

目前Mpx框架已经在滴滴内部大量使用,支撑了滴滴出行、青桔单车、街兔电单车、营销、车服等业务在小程序上的实现,线上运行稳定,收到了大量的好评反馈。将来咱们在对框架进行持续迭代优化的同时会持续跟进微信和支付宝最新的技术标准,同时也会将在更多的小程序平台上进行适配。因为咱们的设计初衷和专一点在于加强小程序开发体验,Mpx并无进行跨H5甚至是跨Native的支持,但现实业务当中确实存在这样的诉求,将来咱们会在Mpx的基础上对跨端进行必定的尝试,与此同时咱们依然会持续维护升级Mpx,缘由在于跨端意味着灵活性受限及能力的缺失,咱们但愿能给用户提供第二种选择。

Mpx与业内主流小程序框架异同对比

WePY mpvue Taro Mpx
代码规范 自定义 Vue React 小程序+
组件化实现 Page封装 Page封装 Component Component
数据响应 脏值检查 Vue Mobx
状态管理 Redux Vuex Redux 类Vuex

结语

若是你注重开发体验和产品性能,专一于小程序开发,那Mpx会是一个很好的选择。最后感谢开源社区源源不断涌现出的优秀项目,给咱们提供了无限的启发和巨大的技术帮助。

Github: github.com/didi/mpx

使用文档: didi.github.io/mpx/

用户交流: 点我进群

相关文章
相关标签/搜索