微信小程序多个插件结合研发架构

简述

如何开发一个插件(戳这里)并不会过多说明,也相对简单。不过当业务体系需要由多插件共同来运作时,那么如何处理插件与插件间的关系,如何处理插件与小程序间的关系,一旦插件数增多研发体系则会变得极其复杂。往往采用插件模式做业务支撑时,每一个插件开发背后可能是一个部门,或者是一个公司,那么跨团队或跨企业的协作开发是很艰难的。

小程序如何插件化

插件开发和小程序开发非常相似,小程序的代码可以直接移植到插件中,开发上只有几点需要注意:

  1. 请详细查看插件的 API 限制。
  2. 授权相关的需要使用插件功能页,配合小程序一起开发。
  3. 开发模式使用插件开发模式,而不再是小程序开发模式。
  4. 插件提审需要编写开发说明文档。

(注:文档说明很重要,没有提及的社区也都有说明,只要是小程序上的业务,插件中也一定有办法实现的)

多插件接入基础规范

为什么要设定插件的基础规范,也就是插件的接入要求(这块内容,往往是小程序方会有要求)。

1.体积

首先很重要的一点就是“体积”问题,整个小程序的体积限制是 20MB,同时每个分包的限制是 2MB,插件的体积是会计算到每个引用的包内,那么插件体积必须在 2MB 内(最低要求),但是往往我们要提前预设后期的发展规划,小程序会达到的上限,以及留给插件体积的上限,以及预计插件的接入数。同样的还需要考虑的一点是,如果插件是以组件的形式接入,那么一般是放主包内的,那么组件插件的体积就一定要好好限制,建议接入主包的插件尽量都在 100KB 内吧。

2.参数

其次需要定义主程序能够提供给插件的“参数列表”,一般需要包含的数据有appId,mobile,openId,timestamp,sign,debug,包含了用户信息,加密签名,以及环境切换(注:因为涉及到多插件间的联调,环境切换需要改为运行时,这个很重要)。

3.基础库

然后我们还需要定义调式基础库版本,目前建议 2.11.1。

4.版本更新

1
2
3
4
5
[XXX 插件名称] [版本号]1.0.2
A:新增 XXXXXX 功能
F:修复 XXXXXX 的缺陷
U:更新 优化 XXXXX 流程
U:更新 优化 XXXXX 流程

(注:当然还有更多的规范可以做定义,包括服务端接口规范,压测要求,账号同步流程,订单等等就不过多说明了)

插件功能模块分配

首先如果是在主包中存在插件组件的,那么为了保障主包的大小,以及首次加载体验,我们可以将插件组件中的二级内容,移动到分包插件中,原则上就一句话,“尽量保证主包足够小。”

然后如果由于业务原因,我们存在主插件和分插件的概念,那么可以在主插件中暴露一部分基础能力,比如说登录授权,用户信息,网络请求,数据统计等基础功能,从而减少总插件的体积。

如果各个插件完全不存在关联性,那么就只能各自管理各自的,但同样的主程序可以暴露一些基础功能,比如加解密库,路由处理等等。

插件基础能力拓展

插件中存在部分基础能力限制,那么可以通过小程序 Bridge 的方式给插件做拓展。方案图如下:

插件间相互交互

插件间的交互其实就如文档说明的一样,不外乎跳转其他插件页面,加载其他插件组件,调用其他插件方法。插件方法,建议可以暴露一个消息通信对象,多插件间共用消息通信(可用 EventEmitter),具体如下:

1
2
3
4
5
6
7
8
const xxPlugin = requirePlugin("xxPlugin"); // 获取xx插件的暴露对象

xxPlugin.EventEmitter.off("getUserInfo"); // 移除重复监听
xxPlugin.EventEmitter.on("getUserInfo", () => {
xxPlugin.EventEmitter.emit("setUserInfo", {
mobile: "xxxx",
});
});

(注:在插件组件不支持 wx.navigateTo 等路由 API,可以通过 Bridge 的方式拓展基础能力。在插件中使用 Bridge,可能会遇到 wx 作用域的限制,可以在插件调用 Bridge 时绑定 wx 作用域。)

多插件间的联调模式

当开发一个插件时,可以通过插件开发模式,调试单个插件,但若是涉及到多个插件需要联调时,那么只能以小程序的模式,加载多个插件进行测试。可以通过提供插件开发版本号,集成到主程序的开发版中进行集成测试。这时运行时环境切换的功能则非常重要了,同一份代码就方便调试正式和测试环境,而不用频繁的进行打包操作。

值得一提的是,当多团队开发时,往往插件开发者不具有小程序的开发权限,所以无法做到快速的集成调试和修改。那么建议各个插件开发者们,自研一个模型小程序,保持运行环境与主程序一致,可以极大的提高开发调试的时间。

研发的故事

某一天,突然接到老板的需求,说是我们要将我们的所有业务快速接入到某个大厂的小程序中,很重要,很紧急。行吧,那我们就开干吧,大厂那边提了很多要求需要通过小程序插件的形式接入过去,好的那就先看一波文档。初期接触沟通下来,感触颇深的是,大厂那边提的较多要求,也做了很多标准化,这确实是比我们日常的验收标准要高不少呢。

经过多次激烈讨论后,需求一期我们决定将所有的业务模块,划分为三个插件提供给接入方。为何拆成三个?不要多想。初期确实没有过多的考虑架构,也没有什么特殊原因,就是因为业务内容太多了,所有代码放在同一个插件内,那是完全放不下的,那就按照业务拆成了三个。因为需求,我们的首页插件需要以组件的形式,放入到小程序首页中,其余两个倒是就单独的插件业务。往往接触新的内容,开发初期就是读文档,那时读需求文档时,好像看到首页插件要求是体积必须限制在 500KB 以内(哭,看错了,其实真实要求是 100KB 以内),那么我们就规划了将重业务都放其余插件中,尽量让首页插件轻量。了解大概内容后,开干开干…

经过几天努力,三个插件的内容都已基本开发完成,那么问题来了,我们该怎么确保插件间的相互交互都是稳定的呢?难道单纯的理论上可行则就可以了嘛(这不现实)。一番思考之后,那么我们就做一个测试小程序吧,so easy。一顿操作之后,把我们的三个插件都载入进去了,然而发现预览不了,体积严重超过限制。那么再操作,每个插件都搞成了单独一个分包引入。其实操作过程中还有奇怪的点,明明上传的单个插件体积没有超过 2MB,但是到集成后预览时显示的是插件体积超过了 2MB,当时没有深入研究,可能是编译后的代码和运行时的代码量不同造成的。

到了交付时间,我们将插件开发版本号提供给大厂研发,做了第一次对接。很不幸运,完全没有跑起来,一番排查下来,主要有几个问题,首先我们的首页插件太大,主包集成不了,就是之前说的需要在 100KB 以内。然后是我们插件内部逻辑互相引用的插件名和小程序引入的插件名不同,导致一直调用失败。经过一番激烈操作后,我们统一了插件名,方法名,参数名等等各种命名规范。再然后我们还发现,在业务模块中,因为需要授权做支付操作,那么因为插件的权限限制,则需要用到插件功能页(这个在开发环境下,需要提前加载开发版小程序),所以又是一顿操作,给相关人员都添加了开发权限。当然还有数不胜数的小问题,那都可以直接忽略。

验收过程中,因为大厂方的测试标准要求更高一点,所以频频反馈出各类需要优化的点(这一定是 PUA)。不过后来我们发现这确实需要标准定高一点,不然在大流量的加持下,所有的小问题都直接被放大化了。与其等到用户反馈,那还不如在开发阶段就提前解决。

最后直到整个项目上线,我们才算是可以松了一口气。在这中间确实优化了很多的细节问题,不过收益也是可观的,据统计初期在灰度上线期间整个小程序的流量在 300W+,那么全面开放后预测能够达到亿级别,同样的这部分流量分散到各个插件业务内容中也相对很可观。面对如此大的流量,我们要做的则是在后期的迭代中,将体验做得更好,将项目变得更稳定。

值得一提的是,在后期的迭代中,也有其他业务插件接入方对接到小程序,当然我们不清楚他们背后的插件架构体系是如何的,但从研发周期上可以侧面反映出,我们的研发效率至少在其 3 倍以上。可能我们在插件开发的技术实现上,相差无多,但是放大到整个插件研发的流程化,工程化上,可能就相差甚远。我们确实花了大量的精力去思考,如何让产品迭代更快速,如何让项目更稳定,如何让开发少加班。

文章作者: 方长_beezen
文章链接: https://dongbizhen.com/posts/40549/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 BEEZEN