滴滴开源小程序框架 Mpx 新特性:局部运行时能力增强

这篇具有很好参考价值的文章主要介绍了滴滴开源小程序框架 Mpx 新特性:局部运行时能力增强。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Mpx 是滴滴开源的一款增强型跨端小程序框架,自 2018 年立项开源以来如今已经进入第六个年头,在这六年间,Mpx 根植于业务,与业务共同成长,针对小程序业务开发中遇到的各类痛点问题提出了解决方案,并在滴滴内部建设了完善的小程序跨端开发生态。目前,Mpx 已经覆盖支持了滴滴内部全量小程序业务开发,成为了滴滴小程序开发的统一技术标准。

本文主要探讨MPX局部运行时能力增强的方案设计。如需深入了解滴滴开源项目MPX,请参阅相关文章:

滴滴开源小程序框架Mpx,致力于提高小程序开发体验

滴滴出行小程序体积优化实践

滴滴小程序框架Mpx发布2.0:可直接转换已有微信小程序

小程序框架Mpx的下一代脚手架升级之路|滴滴开源

滴滴小程序开发标准 Mpx 推出新版本,聚焦性能与包体积优化

目前在小程序社区当中存在两种小程序上层框架技术方向:

  1. 以 Mpx 为代表的重编译框架,源码采用小程序平台的dsl,编译后直接产出满足小程序规范的代码

  2. 以 Taro@3.x 为代表的重运行时框架,源码可以使用 Vue、React 作为上层dsl,在运行时当中注入框架代码,同时 polyfill 掉小程序在逻辑线程当中并不能访问的 Dom、Bom 等相关 api

由于技术选型和设计思路的差异,小程序框架的发展及开发者实际开发过程中面临的问题侧重点也有所不同。

对于小程序框架自身的迭代:

  • 重运行时框架已具备现代Web框架开发的效率和体验,主要解决Web标准与上层框架和小程序平台规范的差异性和兼容性问题

  • 重编译框架遵循小程序平台的开发规范,核心在于增强小程序能力,提高开发效率和体验,尽量与现代Web框架能力对齐

Mpx 正是在小程序能力增强的设计思路下,努力与现代 Web 框架的开发体验和能力拉齐,以全面提升用户的开发效率、体验及小程序性能。例如,近两年发布了两个 minor 版本,分别支持了 webpack5 持久化缓存来大幅提高编译构建速度以及 composition-api 特性,让用户能够使用当下最热门且备受好评的开发范式。

在实际业务开发过程中,如果想要使用 props 透传、默认插槽、事件透传等现代 Web 框架提供的功能,但由于小程序自身框架设计未支持这些特性,开发者需要编写大量冗余代码才能达到相同的效果。因此,为了尽可能与现代 Web 框架能力拉齐,我们需要在运行时层面进行能力增强,以提高用户的开发效率和体验。这就是接下来要介绍的 mpx 局部运行时方案设计。

方案设计

在整体的技术方案设计上还是按照小程序能力增强的思路进行,以最小的组件粒度来按需开启运行时渲染。

滴滴开源小程序框架 Mpx 新特性:局部运行时能力增强,小程序

在具体实现上分为运行时和编译两部分内容。

在编译阶段主要完成:

  1. Render Function 增强

  2. 基础模板按需生成

  3. 胶水代码注入

在运行时阶段主要完成:

  1. propertiesToComputed

  2. vdom tree 生成&视图渲染

  3. 组件实例上下维护

  4. 事件代理&分发

滴滴开源小程序框架 Mpx 新特性:局部运行时能力增强,小程序

核心模块设计

render 函数增强

Mpx 在视图层处理上严格遵守小程序开发规范:一个Mpx SFC文件经过编译后,其处理完成的template将被输出为符合小程序语法规范的wxml静态文件。

在性能优化方面,Mpx 引入了 render 函数。目前,render 函数的主要功能是收集响应式数据。在组件初次渲染阶段,调用 render 函数完成响应式数据的收集。当响应式数据发生变化时,重新触发 render 函数的执行,完成变更后数据的收集,然后进行数据 diff,最后通过 setData 完成页面UI视图的更新。render 函数的形式如下:

global.currentInject = {
  moduleId: "m3f28ff60",
  render: function () {
    this._c("message", this.message);
    ({ tap: [["onViewTapBubble", 'b', "__mpx_event__"]] });
    this._i(this._c("navigatorList", this.navigatorList), function (item, index) {
      ({ tap: [["jumpTo", item]] });
      item.name;
    });
    this._r();
  }
}

在运行时增强方案中,Mpx SFC 文件经过编译后,对于 template 处理最大的不同在于经过编译后是处理为一个执行后会生成 vdom tree 的 render 函数。

在组件初次渲染过程中,执行这个 render 函数,不仅完成了响应式数据的收集,还生成了 vdom tree 。这个 vdom tree 描述了 template 的内容,并将它注入到运行时的 render 函数中。因此,在页面的初次渲染阶段,setData 设置的数据是整个 vdom tree ,它描述了整个模板视图的内容。然后通过自定义容器组件 mpx-custom-element 的递归渲染来完成整个组件的渲染。

global.currentInject = {
  moduleId: 'm3f28ff60',
  render: function () {
    var vnode = this.__c('block', [
      this.__c(
        'view',
        {
          class: this.__sc('root', undefined),
          mpxbindevents: {...},
          eventconfigs: {...}
        },
        [
          this._i(
            this._c('navigatorList', this.navigatorList),
            function (item, index) {
              return this.__c(
                'view',
                {...},
                [...]
              )
            }
          )
        ]
      )
    ])
    this._r(vnode)
  }
}

在组件初次渲染时,通过 setData 传递到渲染层的数据是全量的 vdom tree。当组件响应用户操作或接口请求导致组件实例上的响应式数据发生变化时,会触发 Render Function 的重执行,以生成一个新的 vdom tree。考虑到逻辑层与渲染层通信的成本和性能,这涉及到前后两次 vdom tree 的 diff。最终,生成具体的 vdom 路径数据更新内容,并通过 setData 传递到渲染层,完成视图的局部更新。

mpx-custom-element 容器组件

mpx-custom-element.mpx 是 mpx 内置的一个自定义组件,主要用于运行时渲染。其主要功能有两个:

  1. 作为基础容器组件承载模板渲染:mpx-custom-element.mpx 主要作为一个渲染容器,接收组件传递的需动态渲染的 composed tree 数据,并在其上下文中完成真实组件的渲染。需要注意的是,mpx-custom-element.mpx 本身也是一个基于模板动态渲染的组件,其最终编译输出的内容包含 wxml(视图层)/wxss(样式)/js(逻辑层)/json(配置)。

  2. 跳脱微信小程序模板递归渲染的限制:由于微信小程序的 template 能力不支持模板的自引用递归渲染,因此需要借助一层自定义组件容器来绕开这一限制,从而提供新的渲染上下文。

基础模板

所有模板动态化组件的视图都是基于 mpx-custom-element.mpx 提供的基础模板 mpx-custom-element.wxml 进行动态渲染的。在组件的编译阶段,会按需收集使用到的组件和属性,并将其输出到基础模板中,以确保基础模板的包体积最小化。

组件的 Render Function 执行后生成的 vdom tree 描述了组件的视图层结构和样式。最终,通过组件实例的 setData 方法将 vdom tree 传递到视图层,并利用这些基础模板进行动态渲染。

<template is="tmpl_0_container" wx:if="{{r && r.nodeType}}" data="{{ i: r }}"></template>


<template name="mpx_tmpl">
  <element r="{{r}}" wx:if="{{r}}"></element>
</template>


<template name="tmpl_0_block">
  <block wx:for="{{i.children}}" wx:key="index">
    <template is="tmpl_1_container" data="{{i:item}}" />
  </block>
</template>


<template name="tmpl_0_view">
  <view class="{{i.data.class}}" bind:tap="__invoke" data-eventconfigs="{{i.data.dataEventconfigs}}" style="{{i.data.style}}"  data-mpxuid="{{i.data.uid}}">
    <block wx:for="{{i.children}}" wx:key="index">
      <template is="tmpl_1_container" data="{{i:item}}" />
    </block>
  </view>
</template>


...

事件系统

小程序采用双线程架构(视图层+逻辑层),在其事件系统设计中:

  • 事件是视图层到逻辑层的通讯方式

  • 事件可以将用户的行为反馈到逻辑层进行处理

  • 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数

同时,小程序的事件模型(事件冒泡、事件捕获)在视图层进行声明,而非在逻辑代码层通过 API 调用的形式实现,这也是小程序的事件系统和 Web 事件系统的最大差异点。

由于小程序没有真实的 DOM/BOM,其他运行时方案中的事件系统需要基于 vdom tree(vdom tree 上绑定了不同节点的事件处理类型&函数)按照浏览器的事件机制实现相关的事件流程(事件冒泡、事件捕获)。在整个事件系统处理的方案中,完全由运行时接管事件触发的生命周期。简单总结流程如下:

  • 由小程序的视图层接收事件的触发

  • 视图层与逻辑层通信,将用户行为反馈到逻辑层处理

  • 运行时代码模拟整个事件系统生命周期

<view
  bindtap="__invoke"
  bindtouchstart="__invoke"
  bindtouchmove="__invoke"
  bindtouchend="__invoke"
  bindtouchcancel="__invoke"
  bindlongpress="__invoke"></view>

可以看到在基础模板上,我们只对普通的事件如 tap、touchstart 等进行了绑定(在模板上没有绑定其他特殊的事件类型),同时每个事件使用__invoke 代理方法统一响应微信小程序触发的事件。在其他运行时方案(以 Kbone 为例)中,运行时代码实现了一整套事件系统,在__invoke 代理方法内部根据实际的事件类型触发相应的事件,并根据 vdom tree 递归寻找事件触发的上层节点,从而模拟出事件冒泡的流程,事件捕获的流程同理。

然而,在 mpx 运行时能力增强方案中,整个方案设计的出发点是按组件粒度使用。如果事件系统也采用这种运行时模拟事件生命周期的方式,将无法很好地与微信小程序的事件机制贴合在一起:主要体现在事件的生命周期无法统一(一个是视图层的声明式,另一个是逻辑代码层的 API 形式)。因此,在 mpx 运行时能力增强方案中,针对事件系统的设计仍然遵循微信小程序的事件系统设计:视图层的声明式。我们不单独实现一套基于 vdom tree 的事件系统。

为了实现这一目标,在运行时组件的模板编译过程中,我们会收集那些使用了 catch、capture-bind、capture-catch 特殊事件生命周期的节点。这些节点最终会被注入到 mpx-custom-element.wxml 基础模板中,同时会根据节点的属性生成对应的 template 模板内容。这样,最终运行时组件的事件生命周期也与微信小程序保持一致。虽然使用了特殊事件生命周期的节点会被注入到基础模板中,导致 mpx-custom-element.wxml 基础模板的最终体积有所增加,但在我们实际使用的场景中,例如乘客主小程序里使用特殊场景事件的情况少之又少,所以这部分的基础模板体积增加是完全可接受的。

性能相关

对于运行时方案来说,小程序的渲染性能是需要特别关注的地方。相较于编译型框架,随着项目复杂度的提升,运行时方案的整体渲染性能表现可能会较差。

有几个比较典型的场景:

  • 页面初次渲染:对于 mpx 项目,最终页面的模板存在于视图层,渲染只需将模板中使用到的数据传递到视图层。而在运行时方案中,逻辑层需要将全量的 vdom tree 数据传递到渲染层驱动基础模板的渲染,因此整体的数据量会大得多。

  • 页面二次更新渲染:对于 mpx 项目,基于 Render Function 的数据 diff 最终只会收集发生变化的 key 以及 value。然而,对于运行时方案,例如使用 Vue 的 Taro 项目,如果响应式数据发生变化,重新触发 Render Function 执行及后续的 diff 操作,需要准确找到数据发生变更的 vdom 节点信息,因此传输的数据量相较于编译型框架而言也会更多。

在 mpx 运行时渲染中,同样会遇到这些性能问题,但在具体的实现过程中,我们会尽量将一些对性能有影响的点降到最低:

  • 首先,在运行时方案的整体策略上,mpx 运行时的能力是按需的,做到局部开启组件的运行时特性。因此,对于一个页面而言,可以部分走原有的编译方案,部分走运行时的方案。

  • 其次,相较于纯运行时方案,它们的基础模板基本要做到全量的输出,而在 mpx 局部方案中,我们是按需完成基础模板的收集和输出,同时对于模板节点的属性、事件绑定也能做到按需。

小程序基于运行时的能力拓展

对于运行时方案来说,它提供了一种新的逻辑层控制视图层渲染的方式。从某种程度上说,小程序的运行时渲染可以看作是对原生小程序能力的增强,这为小程序的能力拓展带来了更多的可能性。

例如,React 提出的 Server Components,通过调试官方提供的 demo,我们可以大致了解其工作流程。简单来说,前端通过接口(props数据)驱动后端 Server Components 的执行,生成描述前端页面结构的 ast json,然后这部分数据再驱动前端完成最终的视图渲染。

使用 Server Components 会带来以下好处:

  • Zero-Bundle-Size Components(在 server 端运行的组件及其纯 js 依赖最终并不会被下载到浏览器当中运行)

  • loading performance(Server Components 可以直接访问后端的服务or database,对于一些场景可以减少网络请求数量,同时把一些纯计算的工作可以放到 server)

那么,在小程序场景下,借助运行时的能力,我们是否可以尝试实现类似 Server Components 的功能呢?暂时抛开工程方面的问题,针对目前小程序的技术架构,可能会遇到以下的问题。

视图渲染

在小程序场景下,视图层渲染有两种方案:一种是原生小程序的渲染流程,另一种是运行时渲染流程。以 mpx 运行时能力增强为例,编译环节将 template 转换为可执行的 Render Function,运行后生成描述视图的 vdom tree,然后驱动视图层的基础模板进行渲染。在这个过程中,Render Function 的执行实际上是由 props/data 的变化驱动的,与平台和环境(例如不依赖小程序提供的API)无关。因此,Render Function 也可以在 server 端执行,生成描述视图的 vdom tree。

既然在 server 端可以实现与原本在小程序环境下相同的效果,那么小程序通过接口获取到这部分数据后,后续的流程就可以交给运行时方案接管,完成最终的渲染。

滴滴开源小程序框架 Mpx 新特性:局部运行时能力增强,小程序

样式规则

对于 wxss 样式规则而言,需要注意的是:在小程序的技术架构中,开发者工具在编译构建阶段会将 wxss 和 wxml 提前处理为可执行的函数,这些代码最终在小程序运行时被注入到视图层执行。

然而,在 Server Components 中,样式规则不再是静态数据,而是由业务后端接口下发。这些数据最初存在于逻辑线程中。为了使逻辑线程中的样式规则能够在视图层生效,有且仅有一个方案就是在 Render Function 执行完生成 vdom tree 后将样式规则通过 inline 的方式合并到最终需要被渲染的 composed tree 当中。       

滴滴开源小程序框架 Mpx 新特性:局部运行时能力增强,小程序

组件逻辑

对于一个组件来说,通常包括由外部传入的 props、自身的状态、生命周期、事件处理(用户交互)等方面。首先,我们可以明确的是,小程序组件的生命周期脱离了小程序平台是无法正常运行的,同时事件也需要在用户发生交互行为后才能触发。因此,对于组件本身而言,这部分内容无法像视图层渲染那样将js代码存放在远端并通过接口/cdn 的形式下发,而只能随着小程序的上线发布存在于逻辑线程中。这样,组件的生命周期和事件交互等方法可以与原有的执行策略保持一致,确保其正常工作。对于事件的处理,与运行时方案一致:通过事件代理的形式来分发真实的用户操作。

实际上,这在 server components demo 中也可以清晰地看到不同类型的组件的职责划分非常明确:

  • 对于 x.server 组件而言:由 props 驱动(props 来源可以是 client 的请求,也可能是服务端访问其他服务或 database),不涉及组件自身状态的维护、生命周期、用户事件交互,只做纯渲染工作;

  • 对于 x.client 组件而言:在浏览器中执行的代码与普通组件无异,可以进行任何操作。

server components 和 client components 混合渲染

在 RFC 中也提到了 server components 和 client components 相互引用的场景。其中,server components 最终在服务器端运行并生成 vdom tree,而 client components 则仅通过一个组件标识下发,其实例的创建在浏览器端执行。

在小程序运行时方案中,也存在类似的场景:部分组件采用运行时渲染,这些组件可能会引用原生的小程序组件,这意味着组件内部存在两种不同的组件渲染方式。对此,我们有相应的解决方案:将原生的小程序组件作为依赖注册到基础模板容器组件中,基础模板最终也需要生成原生组件。

结语

Mpx 作为一款兼具优秀开发体验和深度性能优化的增强型跨端小程序框架,我们一直致力于在此领域持续前进,同时也诚邀大家加入 Mpx 用户群,共同参与和交流。

滴滴开源小程序框架 Mpx 新特性:局部运行时能力增强,小程序

滴滴开源小程序框架 Mpx 新特性:局部运行时能力增强,小程序

点阅读原文,跳转项目官网文章来源地址https://www.toymoban.com/news/detail-830971.html

到了这里,关于滴滴开源小程序框架 Mpx 新特性:局部运行时能力增强的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 框架:提供一定能力的小段程序

    2017年Android百大框架排行榜 随意转载,标注作者 \\\" 金诚\\\" 即可 本文已授权微信公众号:鸿洋(hongyangAndroid)原创首发。 本文已经开源到Github上,欢迎各位共同编辑、参与到榜单的建设中来 Github 地址     排行榜包括四大类: 单一框架:仅提供路由、网络层、UI层、通信层或其

    2024年02月08日
    浏览(43)
  • 微信小程序的特点、开发能力及运行机制

    小程序的特点 1、相比于传统应用,有以下特点: 与web相比,首先入口不同。 主要都是基于传统的前端技术,以JavaScript语言为主。 与APP相比,学习门槛和开发成本都比较低,可以快速上手。 不需要下载和安装,不想用了也不需要卸载。 相比h5,小程序受限微信运营规范,不

    2024年02月11日
    浏览(40)
  • 国内大模型在局部能力上已超ChatGPT

    中文大模型正在后来居上,也必须后来居上。   @数科星球原创 作者丨苑晶 编辑丨大兔 从GPT3.5彻底出圈后,大模型的影响力开始蜚声国际。一段时间内,国内科技公司可谓被ChatGPT按在地上打,毫无还手之力。 彼时,很多企业还不知大模型为何物,GPT3.5就已够生成诸如营销文

    2024年02月14日
    浏览(45)
  • Go 开源库运行时依赖注入框架 Dependency injection

    一个Go编程语言的运行依赖注入库。依赖注入是更广泛的控制反转技术的一种形式。它用于增加程序的模块化并使其具有可扩展性。 依赖注入是更广泛的控制反转技术的一种形式。它用于增加程序的模块化并使其具有可扩展性。 Providing Extraction Invocation Lazy-loading Interfaces Gro

    2024年02月07日
    浏览(53)
  • 一、课程设计目的与任务《数据结构》课程设计是为训练学生的数据组织能力和提高程序设计能力而设置的增强实践能力的课程。目的:学习数据结构课程,旨在使学生学会分析研究数据对象的特性,学会数据的组织方法,以

    一、课程设计目的与任务 《数据结构》课程设计是为训练学生的数据组织能力和提高程序设计能力而设置的增强实践能力的课程。目的:学习数据结构课程,旨在使学生学会分析研究数据对象的特性,学会数据的组织方法,以便选择合适的数据的逻辑结构和存储结构以及相应

    2024年02月21日
    浏览(71)
  • DoKit:一机多控WebView无侵入注入JS|滴滴开源

    将滴滴技术设为“ 星标⭐️ ” 第一时间收到文章更新 导读 自2018年正式对外开源以来,DoKit经历了五年的打磨,已经发展成一个相对完整的生态,支持六大平台(Android、iOS、Web、小程序、Flutter和PC),是滴滴开源委员会的精品孵化项目。在外部被众多头部企业广泛使用并获

    2024年02月15日
    浏览(38)
  • 基于51单片机的压力监测仪(MPX4115)(Proteus仿真+程序)

          本设计由51单片机最小系统+MPX4115压力传感器+ADC0832模块+液晶1602模块 1、主控制器是AT89C82单片机 2、MPX4115压力传感器采集气压力,通过ADC0832模数转换器进行A/D转换,读取压力数据 3、液晶1602显示其压力值 Proteus7.8以上版本均可使用 28、基于51单片机的压力监测仪(MPX4115

    2024年02月01日
    浏览(62)
  • 基于单片机压力传感器MPX4115检测-报警系统-proteus仿真-源程序

    一、系统方案 本设计采用52单片机作为主控器,液晶1602显示,MPX4115检测压力,按键设置报警,LED报警。 二、硬件设计 原理图如下: 三、单片机软件设计 1、首先是系统初始化 /******************************************************************* 液晶初始化 ******************************************

    2024年02月09日
    浏览(51)
  • 玩转Google开源C++单元测试框架Google Test系列(gtest)之六 - 运行参数

    目录 一、前言 二、基本介绍 三、参数列表 四、XML报告输出格式 五、总结 使用gtest编写的测试案例通常本身就是一个可执行文件,因此运行起来非常方便。同时,gtest也为我们提供了一系列的运行参数(环境变量、命令行参数或代码里指定),使得我们可以对案例的执行进行

    2024年02月07日
    浏览(71)
  • 如何利用Flutter框架开发运行小程序

    Flutter 是一个非常优秀的开发框架,借助 Flutter,开发者可以在 iOS 以及 Android 平台自由地发挥创意,构建交互丰富的、精美的应用程序。 Flutter产品团队透露,创建Flutter的初衷是试图彻底改变应用开发:将网络的迭代开发模式与硬件加速图形渲染和像素级控制相结合,而这在

    2024年02月08日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包