导语

本文分享58安居客小程序团队在小程序向平台化转型、多小程序同步开发过程中遇到的问题、解决方案与实践。

背景

在提效、服务进阶的大背景下,为了让同一支团队,把一个业务做精做深,提高研发效率,HBG的产研团队,进行了新的划分:分线开发。

分线开发以后,安居客二手房前端团队要维护小程序从 1 变成 4 个。

小程序 技术栈
安居客微信小程序 微信原生开发
安居客百度小程序 百度原生开发
58二手房小程序 mpvue
58同城小程序房产二手房业务 插件方式接入,技术不限

与此同时,随着移动互联网的流量红利逐步减少,小程序无疑是新的流量风口,为了抢占更多免费流量,推动业务快速发展,产品希望我们安居客微信、百度小程序可以同步开发,以及未来可以支持更多小程序,如快应用等。
在多小程序技术框架不同、业务逻辑不同、基础能力不同的情况下,给我们的小程序开发带来了以下挑战:
1、在人力不变的情况下,我们要如何支持多个小程序业务需求快速迭代?
2、作为平台方,我们要如何与业务方协作开发?
3、如何支持房产垂直业务在其他小程序平移?
面对这种变化,我们联合房产各业务前端、产品、UED、QA等多个团队,一起发起了小程序七巧板项目,也开启了58安居客小程序打怪升级刷新副本之路,接下来我将娓娓道来我们是如何刷新副本的。

现状分析与设计

1、 现状分析
面对多小程序同步开发的需求,我们应该如何做呢?
1) 方案一:按照小程序端配备开发资源,迭代开发速度不变,人力需要成倍增加。虽然技术不用做大的改动,但是人力成本太高。
2) 方案二:做技术升级改造,实现技术栈业务的统一。房产小程序其中包含了很多业务(租房、商业地产、二手房、新房),几百个页面,大家都停下业务去做技术栈的统一,显然是不现实的。
考虑到这些实际情况,技术方案上只能考虑边做业务边重构,逐步去做统一。2、 整体设计
从业务方的角度来看,我们希望所有小程序平台尽可能提供相同的通用能力,减少业务的适配,业务开发只需关心业务开发,以及实现多小程序端的适配。
从平台方的角度来说,尽可能为业务方提供便利,减少兼容和适配成本。
针对以上情况,我们做出如下设计:小程序七巧板架构图不难看出:
1) 作为平台方,我们有以下任务:
A、多小程序提供统一通用平台能力接口,即宿主环境。
B、统一基础能力,减少宿主环境的适配
C、统一宿主小程序,从而达到可以快速落地其他小程序目标。
2) 作为业务方,实现二手房业务可在多小程序同步开发。
为了支持业务的快速落地,所以我们把平台建设优先级排在第一位。接下来我将从平台化以及二手房业务适配多小程序开发两个维度来阐述。

小程序平台化建设

1、 确认业务方接入方式
截止到目前为止,仅微信平台支持插件,百度和轻应用等暂不支持插件。
考虑到插件和分包的特点以及各业务实际情况,作为平台方我们插件和分包的接入方式均做了支持。业务方可根据自身业务场景,选择合适的接入方式。2、 确认平台通用能力
宿主环境要解决什么问题?
1) 提供平台基础能力和公共方法的调用
2)抹平不同平台的差异
3) 支持业务插件和分包无缝切换
4) 一套代码在宿主环境中一次测试,多端上线
梳理清楚我们要做什么之后,紧接着进入紧锣密鼓的调研设计中,通过全方位调研我们得知, 58同城微信小程序已经有开发过宿主环境,但无通用SDK。房产的宿主环境要兼容房产多个小程序之间的差异,有很重业务属性,也不能复用58同城宿主。
所以最终我们的宿主环境设计如下:
1) 支持新老开发方式共存,推荐使用基于宿主环境开发
2) API方法名、出参、入参和58同城小程序宿主保持一致
3) 安居客特有业务,加入新的API
4) 提供完整demo、完善的文档、测试环境3、 技术选型
工欲善其事必先利其器,要同时开发多个小程序以及未来可能要支持更多小程序,借助一些优秀的框架进行开发,一定会事半功倍。调研了Taro、WePY、uni-app、mpvue、chameleon、百度小程序转换工具以及其他工具,结合团队实际情况,最后我们选择Taro作为我们的开发框架。选择Taro的主要原因:
1) 支持逐步替换,降低项目风险
2) 团队有React 开发经验,也要维护部分React Native业务,技术栈尽量统一
3) 支持动态编译、条件编译,可实现定制化58、安居客主题皮肤
4) 提供转换工具,可把现有微信小程序直接转成 Taro,降低迁移成本
5) 库维护更新比较稳定,社区活跃4、 小程序基础能力统一
随着宿主环境需求分析、技术选型、开发完成以及配合业务方接入过程中,为了减少业务方的适配,我们通用能力做了三个统一:
1) 账号体系:统一接入云账号,统一账号体系
2) 微聊:统一多小程序微聊接入方式和版本以及通用能力,减少宿主和业务的适配
3) 与TEG在云账号、微聊等基础公共能力上,尽量保持多小程序在接入方式、接口设计上统一,减少接入成本。5、 小程序性能优化
前期我们以宿主环境的开发、支持业务快速接入为主,随着业务逐步灰度接入,小程序的包大小也越来越大,性能问题也越来越明显,以微信小程序为例,我们发现:
1) 小程序包大小越来越大
2) 小程序下载耗时明显增加
3) 小程序启动耗时明显增加
那么如何优化呢?通读了一遍官网的性能优化文档,总结出性能优化的三大块
1) 包体积优化(分包、图片CDN、延迟非必须插件、分包预加载等)
2) 请求优化(请求次数、请求阶段等)
3) 首次渲染优化(setData优化、DOM渲染优化等)
问题又来了,如何来找出我们的小程序,这三大块需要优化的具体影响点在哪里?
在开发工具中使用help()方法,使用其中的openVendor方法打开开发工具在小程序框架所在目录。其中有包括以基础库命名的目录和其他帮助文件。如其中有两个工具wcc和wcsc。wcc工具可把 wxml 转换为对应的 JS 函数$gwx(path, global),wcsc 可将 wxss 转换为 css。而基础库目录包括WAService.js 和 WAWebview.js 文件。结合开发者工具命令行中使用document.head可以查看小程序的整个启动流程大致如下:结合微信包的启动流程和微信开发工具的Sources、Audits面板进行性能分析。我们发现可以通过以下几种方式来进行了优化:
1) 减少包的文件大小
 A、小程序本地图片一律替换成从CDN加载
 B、在平台化过程中,随着业务接入、灰度、全量上线,及时下掉老代码
 C、删除历史无用代码
 D、延迟第三方依赖的加载
2) 优化首屏数据请求,来加速首屏速度选择。首屏非必须的数据,延迟加载
3) 优化 setData存储和调用
 A、减少 setData 的频繁调用
 B、减少 data 上的数据冗余,非必要数据不要在 data 上存储
接下来,以安居客微信小程序为例,介绍一下针对延迟第三方依赖的加载,我们是如何做优化的:
1) 业务插件肯定是要延迟加载的,插件在各业务分包引入,这点毋庸置疑
2) 账号体系,我们是直接对接云账号的插件,最开始的做法是在主包中直接引入,文件比较大(434kb)。后续,云账号插件做了重构和升级,文件大小:80.5kb,并且支持分包引入。进而,我们升级了云账号插件版本、以分包的方式引入云账号插件。最终,主包大小减少了 434kb。
3) 微聊,安居客微信小程序最开始引入的是微聊 JS SDK、自己实现 UI,文件大小:20kb。为了统一多小程序微聊通用能力和复用微聊插件现有卡片功能,我们决定微聊统一接入微聊插件,微聊插件大小:335kb。那我们应该如何引入微聊SDK呢?显而易见,2种方案:
 A、直接在主包中引入微聊插件,对主包大小影响比较大,首页、房源列表等可以拿到微聊消息数,现有功能不会受到影响。
 B、不在主包中引入微聊插件,首页、房源列表等业务拿不到微聊消息数。
首页、房源列表效果图如下图,那我们该怎么办呢?图左是首页,图右是二手房房源列表针对上述问题和业务场景与微聊开发沟通,他们可以提供一个消息总数的接口,但是这个消息总数和微聊插件的总数可能不一致,业务上需要做一下降级,与产品一起沟通之后,也能接受这部分的降级。所以,最后微聊插件SDK,我们以分包的方式做了接入,尽可能的保证了主包的大小以及下载速度。
其他优化,就不在这里一一展开了,通过以上初步优化,我们可以看到启动耗时时间、初次渲染时间有了明显的下降,下图是我们优化后小程序性能变化,后面我们将持续优化,为用户提供更好的用户体验。小程序下载耗时小程序初次渲染耗时

6、 规范化、流程化

俗话说的好,打江山容易守江山难,这句话在我们小程序平台化的过程中也适用。
通过一系列开发和技术方案的落地,我们提供了宿主环境和完整的接入文档、开发demo。配合房产各个业务方完成了首次接入,希望后面不费吹灰之力的更新版本即可。然而理想是丰满的,现实很骨感,比如以下问题:
1) 开发过程中遇到宿主环境的Bug找谁解决
2) 平台方测试和业务方测试如何配合
3) 业务方测试完成后如何交接给平台方
4) 谁负责上线,新的需求怎么对接等等
通过解决这些问题并且实际落地实施,我们一起梳理一套完善的标准和规划的开发流程,通过流程的规范化、标准化,来保证我们项目高效开发、沟通、以及项目的顺利上线。

二手房业务跨平台开发

随着平台化的标准化、统一和完善,不难看出,只要58二手房小程序也接入标准的宿主接口,那么二手房业务要适配的小程序的能力基本上就统一了,接下来只需要考虑业务的实现即可。

图左58二手房房源列表,图右安居客二手房房源列表

通过以上图片对比,我们发现业务逻辑差异较大,想要同步开发还存在不少困难,经过与产品、UED一起沟通协商,58、安居客保证页面结构统一,支持业务、皮肤差异性。借助Taro支持多小程序转换,考虑如何实现定制皮肤与实现业务差异化即可。整体设计如下:

打包和集成

1、多程序打包
1) 打包配置
我们按平台、终端打包需要,在 package.json 增加对应 scripts,然后利用 cross-env这个包来设置环境变量,比如在打包安居客微信小程序的时候,设置环境变量 WEAPP=anjuke,代码如下:

{  "scripts": {    "build:weapp": "taro build --type weapp",    "dev:weapp": "npm run build:weapp -- --watch",    "build:anjuke": "cross-env WEAPP=anjuke && npm run build:weapp",    "dev:anjuke": "cross-env WEAPP=anjuke && npm run dev:weapp"  }}

然后在config/index.js里面利用环境变量加载对应小程序的自定义配置,具体代码代码如下:

const WEAPP = process.env.WEAPP ? process.env.WEAPP : 'anjuke'module.exports = function(merge) {    return merge({}, config, require(`./${WEAPP}`));};

此处 config 代表打包通用配置以及默认配置。如 babel、源码目录等。
为了让每个平台、终端打包出来的代码大小都是最优的,利用配置defineConstants 属性配置编译时的全局变量,从而实现小程序按照平台、终端、功能差异上实现条件编译。我们的实践是按照业务平台、平台属性、小程序终端做了划分:

const config = {    defineConstants: {        PLATFORM, // 网站平台 anjuke 或 58        PLATFORM_ABBR, // 小程序名字简写,用来区分同平台同类型小程序        RUN_END, // 运行端 weapp、swan、quickapp                IS_AJK, // 是否是 anjuke        IS_WUBA, // 是否是 58        IS_WEAPP, // 是否是 微信        IS_SWAN, // 是否是 百度        IS_QUICK_APP // 是否是 快应用    }}

在编译的时候,根据目标小程序的特性,为上面变量注入对应的值。
2) 皮肤差异化
二手房业务要同时支持58同城、安居客两个平台。二者之间页面结构是一致的,但各自有些主题色,我们将主题色提取成Sass变量,在编译打包时,按照平台引入平台主题色,从而达到换肤的功能。比如在安居客小程序打包是通过plugins引入安居客主题色:

const path = require("path");module.exports = {    plugins: {        sass: {            resource: [                "src/scss/ajktheme.scss"            ],            projectDirectory: path.resolve(__dirname, "..")        }    }};

2、 API 适配平台、业务差异
58、安居客在业务上存在诸多差异,如账号鉴权、城市、房源展示逻辑等,为了保证小程序在多平台、多终端通用功能统一、前端数据展示逻辑统一,API 接口做了平台、业务、端的兼容,统一了数据接口格式,间接的支持了小程序一套代码在多平台、多端运行。目前我们的落地方案:
1) 按照业务平台划分 API 域名,如安居客小程序接口使用anjuke.om域名,58小程序接口使用58.com域名
2) 按照公参区分终端,如我们通过weapp 公参区分是百度、微信还是其他小程序
以房源列表为例,之前安居客和58房源展示逻辑、扣费逻辑、API接口数据格式等各不相同,重构之后,API根据域名封装业务逻辑,统一接口数据输出格式,比如前端获取列表数据代码如下:

import { fetchList } from "./api";fetchList({    page: this.list.page,    page_size: PAGE_SIZE,    user_id: userInfo.userId || "",    open_id: userInfo.openId || "",    union_id: userInfo.udid || "",    ...this.filterOptions}).then(res => {    // do some thing})

然后我们在 api.js 底层针对58、安居客平台适配一下API接口域名,代码如下:

import { base } from './config';const urlBase = isOldAjk => {  if (IS_WUBA) return base.wbBase;  if (isOldAjk) return base.oldAjkBase;  if (IS_AJK) return base.ajkBase;};

通过API 适配平台、业务逻辑的差异,使前端逻辑在多小程序之间保持独立、统一,从而达到多小程序平移的目的,前端专注于数据展示和交互即可。

3、中间层屏蔽环境、平台差异
同一套代码要运行在多个小程序上,虽然宿主提供了通用标准的能力,但是还有一些差异在短期没有办法解决。为了让同一代码可以在多个小程序之间无缝平移,必然要引用一些中间层屏蔽底层和环境的差异,简化业务调用方式,提高开发效率。
以跳转协议为例,房产二手房的业务要分别以插件的方式集成在58同城微信小程序、以分包的形式集成在安居客微信小程序,那插件和分包在路径跳转方面是不同,为此,有了我们的跳转中间层:

export const goToPage = (wx, params, type) => {    if (MAIN.Common.isWubaPlugin()) {        let isObject = typeof params === 'object';        let entry = isObject ? params : { url: params };        entry.url = `plugin-private://${ pluginId }` + entry.url;        MAIN.Common.goToPage(wx, entry, type);    } else {        MAIN.Common.goToPage(wx, params, type);    }};

4、 统一跳转协议、跳转协议动态下发
现有的多个小程序,之前页面的路由均不一样,在路由跳转管理上、维护和开发成本很高。针对这个问题,我们做了以下几步做了优化提效:
1) 新开发页面多小程序路由保持统一
2) 借鉴58APP协议下发机制,跳转协议统一改为后端下发
这样不仅解决了路由管理维护成本,而且支持更精细化的灰度,做到优雅降级。在我们业务统一逐步切换中,灰度必不可少,有完善的灰度降级方案,也有助于最大限度的降低影响。
具体到业务场景中:以微信小程序为例,提交版本给小程序审核需要时间,在从发版到更新到所有用户,最长需要 24 小时。如果我们新改版的页面上线了,突然发现某些机型打开白页。我们可以快速将下发协议成老页面,甚至换成一个H5的页面,把损失降低到最小。

总结和展望

回顾过去,通过半年多技术和业务的升级和统一。安居客实现了微信、百度、快应用等小程序的平台化,支持房产垂直业务在多小程序上实现无缝平移,可以快速落地生成更多的小程序,同时二手房核心业务完成在多小程序的同步开发,大幅度的提升了小程序开发效率,在小程序的流量风口上为业务落地做好后勤保障。
接下来我们会持续优化小程序性能、完善性能监控、JS错误监控等。拥抱公司小程序协同项目,持续完善安居客小程序平台建设,为业务快速接入、落地做好准备。

写到最后

安居客小程序实现平台化以及实现二手房核心业务重构与顺利落地,离不开其他前端、后端、QA等兄弟团队的支持与积极配合,另一方面,在我们统一小程序基础功能,如云账号、微聊等方面,也离不开 TEG同学的大力支持与帮助,因此在此对你们说一声感谢。个人能力也有限,如果大家发现文章中的错误或者实现方案上的不完美,欢迎交流指正。

参考文献

1、https://developers.weixin.qq.com/miniprogram/dev/framework/
2、https://nervjs.github.io/taro/docs/config.html
3、https://developers.weixin.qq.com/miniprogram/dev/framework/audits/performance.html

作者简介李永超,58集团/资深前端工程师。
张素沙,58集团/高级前端工程师。

END

阅读推荐

金融数仓体系建设数据智能在二手车业务场景中的探索与沉淀-Part2业务标签的挖掘预算平滑技术在58商业的探索与实践房产经纪人页面错误信息采集方案58房产Nginx 网络调优实践如何设计打造金融场景下的业务平台

如何比较两个速度的大小地程序_58安居客小程序平台化与多小程序开发探索与实践...相关推荐

  1. linux怎么比较两个文件大小,linux shell 如何比较两个整数的大小

    linux shell 如何比较两个整数的大小以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! linux shell 如 ...

  2. js判断时间两小时之内_js判断两个时间的大小

    js判断两个时间的大小 function checkdate() { //得到日期值并转化成日期格式,replace(//-/g, "//")是根据验证表达式把日期转化成长日期格式 ...

  3. C语言学习之用函数处理,而且用指针类型的数据作函数参数,对输入的两个整数按大小顺序输出

    对输入的两个整数按大小顺序输出.用函数处理,而且用指针类型的数据作函数参数. int main(){void swap(int *p1,int *p2);//声明swap函数 int a,b;int ...

  4. php 字符串的比较大小,php怎么比较两个字符串的大小

    比较字符串是任何编程语言的字符串处理功能中重要的特性之一.在PHP中除了可以使用比较运算符号(==.)加以比较外,还提供了一系列的比较函数,使PHP可以进行更复杂的字符串比较.如strcmp().st ...

  5. 比较两个数的大小,自定义比较两个整数的大小的方法

    比较两个数的大小,自定义比较两个整数的大小的方法: 如果第一个数大,返回1 如果相等返回0 如果第一个数小,返回-1 在Main()方法中输入两个数,调用这个方法 示例: 请输入两个数: 45 56 ...

  6. JS判断两个日期的差或者判断两个日期的大小

    1.判断两个日期的差: /**计算日期天数差的函数-hanliwei-2013-03-14*/ function DateDiff(sDate1,sDate2) { //sDate1和sDate2的格 ...

  7. 用一句位运算判断两个整数的大小并返回较大者

    2019独角兽企业重金招聘Python工程师标准>>> 用一句位运算判断两个整数的大小并返回较大者,不用if..else,不用循环,不用switch,不用条件运算符 const in ...

  8. linux 用shell比较两个整数的大小

    1.比较两个整数的大小 #1.判断是不是两个数 [ $# -ne 2 ] && { echo "Usage:$0 num1 num2" exit 1} #2.判断是 ...

  9. 比较两个字符串的大小

    题目描述 设计函数,比较两个字符串的大小.每个字符串长度不超过50. 输入要求 从键盘分别读入两个字符串,每个字符串以换行符结束. 输出要求 比较两个串的大小,输出相应的结果. 输入样例 Hello ...

最新文章

  1. Microsoft COCO 数据集
  2. 软件项目版本号的命名规则及格式
  3. python工作-python工作中总结
  4. 史上最黑科技 | 人造肌肉、DNA折叠、柔性外骨骼…
  5. sql server 2008 身份验证失败 18456
  6. day1 -- Python变量、注释、格式化输出字符串、input、if、while、for
  7. 中国塑料泵行业市场供需与战略研究报告
  8. Reflect Refract (以水渲染为例)
  9. 使用fiddler抓取安卓模拟器包
  10. 5901和5909在P570中的功用
  11. MacDev.GarbageCollectionIsDeprecated-WhenXcodeCompileMacAppProject
  12. java毕业设计老师评语_java毕业设计_springboot框架的教师评价评教系统
  13. Pubg九月十六日服务器维护,绝地求生9月16日更新维护到几点?绝地求生9月16日更新时间公告...
  14. 程序猿面试八股文分享~
  15. win11连接不了蓝牙耳机的解决办法
  16. 物联网如何改变医疗保健行业
  17. java中装箱和拆箱的详细使用(详解)
  18. win7桌面计算机丢失,windows7电脑系统文件丢失怎么办
  19. html移动小图标,html5 实现可拖拽移动的悬浮图标
  20. 尚学堂-HTML-CSS(基础)的学习记录

热门文章

  1. 杉德支付php代码实现_[转]PHP语言开发Paypal支付demo的具体实现
  2. SETUP FACTORY安装完成后自动运行软件
  3. Java 8之函数式编程(Function、Consumer、Supplier、Predicate)
  4. [python]WindowsError的错误代码详解
  5. 2020年Java面试题及答案_Java面试宝典_Java笔试题(持续更新中)
  6. 浅谈public static void main(String[] args)
  7. 9、Vue自定义指令
  8. 基于数据指纹的增量式
  9. 关于kali中base64的加解密使用
  10. mysql字段时间类型报异常Data truncation: Incorrect datetime value: ‘2099-01-01 00:00:00‘ for column