滴滴开源小程序框架 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 局部运行时方案设计。

方案设计

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

bee6f53b6272f5a3a20e6a254508ed7d.png

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

在编译阶段主要完成:

  1. Render Function 增强

  2. 基础模板按需生成

  3. 胶水代码注入

在运行时阶段主要完成:

  1. propertiesToComputed

  2. vdom tree 生成&视图渲染

  3. 组件实例上下维护

  4. 事件代理&分发

aaff474fb8a97ac3b265f048bee7e769.png

核心模块设计

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

4830fb9ce9ed0d6420f4eb7d31ce9477.png

样式规则

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

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

aa1a146c85a06b3ea65eec8e64e586c3.png

组件逻辑

对于一个组件来说,通常包括由外部传入的 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 用户群,共同参与和交流。

40e6bada16a0aec9bd85a6f3dc4b898d.jpeg

1504e2dfb0e2c0bd9ebb941e49d311e9.gif

点阅读原文,跳转项目官网

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/350924.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LlamaIndex和LangChain谁更胜一筹?

▼最近直播超级多&#xff0c;预约保你有收获 今晚直播&#xff1a;《LlamaIndex构建应用案例实战》 —1— LlamaIndex OR LangChain&#xff1f; LangChain 和 LlamaIndex 都是 AGI 时代新的应用程序开发框架&#xff0c;到底有什么区别&#xff1f; 第一、LangChain 是一个围…

C++ 之LeetCode刷题记录(十九)

&#x1f604;&#x1f60a;&#x1f606;&#x1f603;&#x1f604;&#x1f60a;&#x1f606;&#x1f603; 开始cpp刷题之旅。 依旧是追求耗时0s的一天。 108. 将有序数组转换为二叉搜索树 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你…

leetcode88合并两个有序数组

力扣&#xff08;LeetCode&#xff09;-合并两个有序数组 方法一 | 合并后排序 题目要求将两个有序数组合并并保证合并后的数组仍然有序。 观察题目可以看出&#xff0c;nums1的容量大小总是 mn&#xff0c;所以 nums2能够合并到 nums1中。 那就将 nums1中未赋值的地方赋上 …

错误票据-蓝桥杯

思路&#xff1a; 其实只是排序一下&#xff0c;然后遍历&#xff0c;如果两个值差2&#xff0c;则输出两个值的平均数&#xff0c;如果两个数差值为0 &#xff0c;那么则这个值就是重复的值 代码&#xff1a; #include <iostream> #include<vector> #include&l…

MySQL 联合索引

文章目录 1.简介2.最左匹配3.最左匹配原理4.如何建立联合索引?5.覆盖索引参考文献 1.简介 联合索引指建立在多个列上的索引。 MySQL 可以创建联合索引&#xff08;即多列上的索引&#xff09;。一个索引最多可以包含 16 列。 联合索引可以测试包含索引中所有列的查询&#…

Elasticsearch8.11集群部署

集群就是多个node统一对外提供服务&#xff0c;避免单机故障带来的服务中断&#xff0c;保证了服务的高可用&#xff0c;也因为多台节点协同运作&#xff0c;提高了集群服务的计算能力和吞吐量。ES是一个去中心化的集群&#xff0c;操作一个节点和操作一个集群是一样的&#xf…

echarts 柱状图数据过多时自动滚动

当我们柱状图中X轴数据太多的时候&#xff0c;会自动把柱形的宽度挤的很细&#xff0c;带来的交互非常不好&#xff0c;我们可以用dataZoom属性来解决 简易的版本&#xff0c;横向滚动。 option.dataZoom [{type: "slider",show: true,startValue: 0, //数据窗口范…

Hive实战 —— 电商数据分析(全流程详解 真实数据)

目录 前言需求概述数据清洗数据分析一、前期准备二、项目1. 数据准备和了解2.确定数据粒度和有效列3.HDFS创建用于上传数据的目录4.建库数仓分层 5.建表5.1近源层建表5.2. 明细层建表为什么要构建时间维度表&#xff1f;如何构建时间维度表&#xff1f; 5.3 轻聚层建表6. 指标数…

实现负载均衡

1.安装依赖 sudo apt insta11 libgd-dev 2.下载nginx wget http://nginx.org/download/nginx-1.22.1.tar.gz 3.解压nginx tar -zvxf nginx-1.22.1.tar.g2 4.编译安装 cd nginx-1.22.1 5.编译并指定安装位置&#xff0c;执行安装之后会创建指定文件夹/www/env/nginx ./configure…

【干货】【常用电子元器件介绍】【电阻】(二)--敏感电阻器

声明&#xff1a;本人水平有限&#xff0c;博客可能存在部分错误的地方&#xff0c;请广大读者谅解并向本人反馈错误。   电子电路中除了采用普通电阻器外&#xff0c;还有一些敏感电阻器&#xff08;如热敏电阻器、压敏电阻器、光敏电阻器等&#xff09;也被广泛地应用。然而…

ubuntu_qtcreator安装

https://download.qt.io/official_releases/qtcreator/ 5.15 以上安装 QT5.15以上不再提供离线安装包&#xff0c;只能在线安装&#xff0c;– 下载 下载地址如下&#xff1a; 腾讯云的国内资源: Index of /qt/official_releases/online_installers/ 官网下载&#xff1a;…

已解决:安卓,怎么优雅接入科大讯飞语音评测功能?

写在前面&#xff1a; 网上关于讯飞接入的博客都很少&#xff0c;按说讯飞都是业界翘楚&#xff0c;不知为何&#xff0c;很少搜索到精品&#xff0c;一搜就是一个要求开会员的博客&#xff0c;我也是醉了。讯飞提供的文档也是不清晰&#xff0c;我是摸着石头过河&#xff0c;…

如何用甘特图跟踪项目进度

甘特图是一个简单但是极其强大的项目管理工具,能够清晰可视化复杂项目的进度,在项目跟踪和控制上发挥重要作用。任何一个严肃的项目组织者都会使用甘特图来规划和管理项目中的任务。 甘特图的纵坐标表示项目的各项活动或任务,横坐标表示项目的时间进度。每个任务用一条横条表示…

掌握Pyecharts:绘制炫酷词云图的参数解析与实战技巧【第36篇—python:词云图】

文章目录 安装Pyecharts基本的词云图绘制自定义词云图样式多种词云图合并高级词云图定制与交互1. 添加背景图片2. 添加交互效果 使用自定义字体和颜色从文本文件生成词云图总结&#xff1a; 在数据可视化领域&#xff0c;词云图是一种极具表现力和趣味性的图表&#xff0c;能够…

C++(搜索二叉树)

目录 前言&#xff1a; 1.二叉搜索树 1.1二叉搜索树的定义 1.2二叉搜索树的特点 2.二叉搜索树的实现 2.1框架 2.2查找 2.3插入 2.4删除 1.右子树为空 2.左子树为空 3.左右都不为空 3.递归版本 3.1前序遍历 3.2中序遍历 3.3后续遍历 3.4查找&#xff08;递…

SPA单页面的讲解(超级详细)

目录 一、什么是SPA 二、SPA和MPA的区别 单页应用与多页应用的区别 单页应用优缺点 三、实现一个SPA 原理 实现 hash 模式 history模式 四、题外话&#xff1a;如何给SPA做SEO SSR服务端渲染 静态化 使用Phantomjs针对爬虫处理 一、什么是SPA SPA&#xff08;sin…

Windows打开IE浏览器命令最简单的方法

问题场景&#xff1a; 许多插件或特定版本的系统需要使用ie浏览器来访问&#xff0c;window默认的ie浏览器是被禁用的如何快速打开ie浏览器解决问题 目录 问题场景&#xff1a; 测试环境&#xff1a; 检查环境是否支持&#xff1a; 问题解决&#xff1a; 方法一 方法二 方法…

支持IPv4与IPv6双协议栈的串口服务器,IPv6串口服务器

物联网是啥玩意儿&#xff1f;这是首先要搞明白的。按照百度百科的说法&#xff0c;是将各种信息传感设备&#xff0c;如射频识别&#xff08;RFID&#xff09;装置、红外感应器、全球定位系统、激光扫描器等种种装置与互联网结合起来而形成的一个巨大网络。这个说法有些复杂&a…

【JaveWeb教程】(33)SpringBootWeb案例之《智能学习辅助系统》的详细实现步骤与代码示例(6)修改员工的实现

目录 SpringBootWeb案例063. 修改员工3.1 查询回显3.1.1 接口文档3.1.2 实现思路3.1.3 代码实现3.1.4 postman测试 3.2 修改员工3.2.1 接口文档3.2.2 实现思路3.2.3 代码实现3.2.4 postman测试3.2.5 前后端联调测试 SpringBootWeb案例06 前面我们已经实现了员工信息的条件分页…

linux jenkins相关命令

1.jenkins启动命令 [rootlocalhost /]#service jenkins start 2.jenkins停止命令 [rootlocalhost /]#service jenkins stop 3.查询jenkins状态命令 [rootlocalhost /]#service jenkins status 4.重启jenkins命令 [rootlocalhost /]#service jenkins restart Jenkins默认的端口号…