44

腾讯在线教育小程序开发实践之路

 4 years ago
source link: https://www.tuicool.com/articles/JfAFvaz
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

作者于2019年6月21日赴北京GMTC大前端技术会议小程序专场,分享话题《腾讯在线教育小程序开发实践之路》演讲稿

一、腾讯在线教育小程序矩阵

首先介绍下腾讯在线教育下的3个主要业务:

  • 面向成人职业化,兴趣化学习的腾讯课堂
  • 面向小学,初高中k12领域的企鹅辅导
  • 面向少儿英语学习的ABCmouse

每个业务下都有PC Web,客户端,H5,APP这几端,来满足学生的多端上课需求。但由于教育的前身是基于QQ群视频孵化出来的,后续也是围绕QQ生态去搭建产品形态,所以在流量上面,QQ相关的流量占比较多。

我们希望能够通过小程序生态,来为教育业务带来微信端流量的增长,并且优化学生的微信端上课体验,所以我们打造了在线教育的小程序矩阵。

我们通过工具,内容型的小程序,来获取流量。比如腾讯课堂打开小程序,腾讯微课堂,企鹅速算,口语拼读等工具型小程序,并最终转化到平台小程序上。

二、小程序基础架构设计及工程化探索

上面提到的那么多小程序,我们是如何进行框架选型 以及团队在多人协作的开发中,是如何制定统一的开发规范,小程序工程化的探索呢?下面将一一介绍。

框架选型时,我们对小程序几大主流开发框架,taro, wepy, mpvue跟原生开发框架进行了对比。可以看出原生框架在CSS预处理,多端复用,管理,自动构建这几块能力对比其他框架是欠缺到。但考虑到以下几点,我们比较倾向于使用原生框架进行开发:

  • 小程序的特性更新迭代速度较快,我们希望能最快使用上最新特性,其他第三方框架可能会有迭代滞后到问题
  • 我们的多端复用需求较弱
  • 对性能调优,问题排查要求较高,希望直接操控原生API

那么以上这些开发上的缺陷,使用原生框架是否可以解决,如何解决呢?

1,CSS预处理

首先来看CSS预处理,我们是期望能够在小程序中使用到CSS预处理,包括嵌套语法,mixin,变量等以及styleLint等工具。 经过调研后,我们可以直接使用postcss来写样式文件并编译处理成wxss。

并且通过引入插件,可以解决小程序样式开发中的痛点。比如postcss-url解决background-image不支持本地图片问题,将其变成base64格式;通过postcss-font-base64插件将字体变成base64格式。

2,数据管理

数据管理方面可以使用westore来接入。

3,构建

小程序的构建需要完成什么事情呢?小程序开发者工具已经提供了部分能力: ES7/ES6转ES5,NPM包管理,代码分包,组件化,打包合并。

我们借助gulp来实现图片压缩以及前面提到的Post CSS编译

为什么使用gulp而不用更流行的webpack呢?

这里补齐的能力主要涉及文件处理比较多,使用gulp开发效率较高,小程序一些官方脚手架也是使用gulp。

最后,我们选择了小程序原生框架作为我们的开发框架。并且补齐了跟其他开发框架对比欠缺的基础能力。当然,这里并非说其他框架不好,具体选择还是需要看具体的业务场景。

确定好开发框架后,统一的目录规范也是团队协同开发必须约束的。

在引入npm包管理后,我们在小程序的基础目录中,通过新起了一个miniprogram目录来作为小程序代码的根目录。这是由于小程序会对node_modules里面的包打包编译到miniprogram_npm目录,为了避免小程序的node_modules跟其他工程化相关的node_modules混在一起,才新起了一个文件夹来存放小程序工程代码。可以通过修改project.config.js可以配置小程序代码的根目录路径。

约束好目录,那么在团队协同开发,如何维护规范化,风格统一的代码,我们希望可以团队成员开发时可以统一代码规范, 提交规范, 风格保持一致。因此,跟我们其他web项目一样,我们可以使用 eslint,stylelint,commitment,prettier等插件来对我们的代码进行约束,规范。通过git hook来在做提交时的校验检测,不通过则不允许提交。

通过Commitizen以及standard-version来自动化生成统一的版本号以及ChangeLog。会自动将你在本次版本迭代中,提交的规范化log(遵循Angular团队的commit规范: https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits )自动生成ChangeLog, 注明是特性发布,bugfix还是breakingChange,以及对应的log信息。后续我们在需要回滚或者回溯某一版本的改动时,就可以一目了然。

我们基于上面的能力以及约束规范,做成统一的脚手架,方便团队在统一的环境下快速开发,并且开源了出去( https://github.com/imweb/generator-imweb-wxapp )。

三、小程序开发实践

介绍完我们的框架选型,工程化探索,接下去分享下在线教育小程序的开发实践经历。

1,小程序音视频

第一部分是小程序音视频能力相关的实践。腾讯课堂是一个在线学习的平台,那么最核心的就是音视频直播,录播能力。那么在小程序上面,我们如何搭建课堂音视频能力呢?

1),直播场景

我们先来看未接入小程序前,腾讯课堂的直播架构。我们通过老师上行到云上,再实时下行到端上, App学生以及通过WebRTC下行到PC web学生。对于延迟要求不高的场景,我们可以将直播流旁路转码到CDN,再供用户拉流观看,以节省成本。

这是各端使用的直播协议以及延迟对比,小程序应该采用那种协议,如何接入呢?

揭秘之前,我们先来了解下小程序音视频能力的发展历史。最初,小程序音视频只有原生的video标签。意味着只能支持 HLS高延时直播场景。

2017年4月份,腾讯云与小程序达成合作,在小程序上嵌入腾讯云音视频SDK,并封装成了live-pusher,live-player标签,使小程序能够支持更低延迟的直播协议,如:rtmp, http-flv等。

因此,我们可以使用live-player来播放rtmp,http-flv协议的流媒体来播放,降低小程序直播场景上的延迟。

不过目前live-player还存在一些不足:

  • 比如全屏按钮不支持,需要自己定义。
  • 由于live-player是原生组件,因此需要通过cover-view以及一些hack方式来实现自定义控制条的全屏按钮跟视频窗口显示层级的bug
  • IOS全屏时,bindevent无效 不过小程序后面采用同层渲染的方案,解决了原生组件需要使用cover-view来解决显示层级问题,使用最新版本的基础库即可。

使用live-player大概1-2s的延迟,那么小程序上还有没更低延迟的直播方案呢?

加入你是在腾讯云上面开通了WebRTC后,可以使用wbertc-room去实现小程序上更低延迟的直播。其原理是基于live-player的RTMP,但走的高速专线,不经过CDN,降低了延迟。

(小程序接入课堂音视频的整体架构图)

2),录播场景

介绍完直播接入方案,接着讲下录播。由于版权保护,腾讯课堂录播播放采用了加密HLS。

由于录播对延迟没要求,小程序上面可以直接使用video标签来播放加密hls流。

在Web上,播放加密HLS的流程如下:

1,获取到加密HLS的m3u8地址,传给video;

2,浏览器video底层解析m3u8,发现其带有加密协议标识-EXT-X-KEY,其值是一个获取解密key的接口地址;

3,浏览器会自动发起该请求,发起请求,去获取解密key;

4,浏览器自动发起请求时,会把用户登陆态通过cookie方式带上,业务后台对cookie鉴权后返回解密key,之后浏览器拿到解密key后就可以解密播放了。

但在小程序中,由于小程序是没有cookie的,那么怎么去针对小程序发起的获取解密key请求鉴权呢?

我们通过在获取m3u8文件时,在meu8地址加入加密后的鉴权参数,并加上前缀"voddrm.token.",这样server返回m3u8文件时,会在EXT-X-KEY的请求地址上,将鉴权参数拼接进去。后面发起请求时,业务后台获取到鉴权参数,按照协商好到方式解密,即可获取到用户登陆票据进行判断是否合法用户。之后就按照之前的流程,鉴权通过即返回解密key。

2,小程序自动化发布

补齐了音视频能力后,我们项目也正常上线。由于平台功能不断增加,小程序也在按照以下流程进行迭代发布。

但是上面流程是存在一些隐藏问题的,特别对于新人,容易因疏忽导致出错,我们也因此导致了一个现网bug。不知道大家能发现不?

揭晓下答案,主要有2个问题:

  • 1,多人开发过程,npm包可能存在不同版本,比如登录能力的npm包,有可能会忘记更新最新包。
  • 2,构建npm按钮在开发者工具上面入口比较隐蔽,容易导致更新了npm包但是忘记点击构建npm,覆盖了线上的特性 上面操作对于熟悉小程序开发的人来说不容易出错,但对于新人,由于不熟悉,容易疏忽。即使犯错但概率很小,但是也必须解决。
    那么我们能否通过自动化工具来帮我们校验检测这些隐患呢?

我们希望在上传发布前,可以进行以下流程的自动检测:

1,代码合并主干检测

2,node_modules版本检测,必须是大于或者等于当前package.json的版本

3,自动执行构建npm操作

4,自动执行上传操作,包括填写版号以及备注信息

其中1跟2可以通过githook以及npm命令来判断,3跟4涉及到小程序相关到能力调用,是否有暴露相关到接口可以调用呢?

这里小程序开发者工具提供了命令行以及http调用方式( https://developers.weixin.qq.com/miniprogram/dev/devtools/cli.html),可以让你操作项目打开/关闭,代码上传,预览,构建npm , 自动化测试等功能。因此,我们利用这个能力,采用cli调用等方式,实现了构建npm以及自动发布等能力。

具体流程如下:

1,进行是否更新最新主干代码检测;

2,判断是否安装了小程序开发者工具且正常设置到环境变量;

3,进行本地node_modules版本检测;

4,调用构建npm命令;

5,自动获取package.json的版本号作为上传版本,获取git 提交log作为备注; 6,调用上传命令进行上传

自动化发布流程示例

3,小程序第三方平台

有了以上工具后,我们就可以愉快地进行开发迭代发布了。但随着我们课堂平台小程序的推广,课堂平台的各家机构都想拥有其自己的机构小程序,并且其页面是课堂平台小程序的一个子集。

通过分析后,我们决定通过构建的方式,从平台小程序中拆离出机构小程序代码。通过2份模版配置信息, 通过构建,可以动态生成平台小程序以及机构小程序的app.json。这样进行上传的时候,就只会上传对应的页面。

代码复用的问题解决了,但随着而来还有另外一个问题。需要生成的机构有80多家,有些机构不一定有开发人员,如果帮助机构快速上传发布他们自己的机构小程序呢?

这里引入微信第三方平台的概念( https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1489144594_DhNoV&token=&lang=zh_CN ),我们可以往微信开发平台申请成为第三方平台。机构申请完独立的小程序账号后,将其授权给我们腾讯课堂第三方平台。这样我们就可以获取到该机构到代码管理,版本发布到权限。通过上传我们之前构建好到机构小程序模版,再调用发布接口,就可以快速实现帮助机构发布其独立个体到机构小程序了。

4,性能优化实践

我们的小程序上线后,通过在小程序管理后台看到的启动总耗时,发现几个问题: 1,小程序管理后台只展示了启动总耗时,下载耗时,渲染耗时这3个数据纬度,但是启动总耗时!= 下载耗时 + 渲染耗时;

2,启动耗时居然达到了3.8s,这是一个合格都数据吗?除了下载耗时跟渲染耗时,其他耗时消耗在哪个环节呢?

要想知道耗时消耗在哪里,首先要先了解小程序启动过程中究竟发生了什么。

1, 小程序初始化

在这个步骤,微信会初始化小程序环境,比如逻辑层的js引擎,视图层的WebView,并且注入公共基础库。

2,下载小程序代码包

这里会进行业务小程序代码包的下载。

3,加载业务代码包

对下载完成对代码包进行注入执行 - 小程序的代码会被加载到适当的线程中执行。此时,所有app.js、页面所在的JS文件和所有其他被require的JS文件会被自动执行一次,小程序基础库会完成所有页面的注册。

4,初始化小程序首页

拉取数据,从逻辑层传递到视图层,生成VD树,进行渲染。

了解完小程序的启动过程后,我们经过分析定位,个阶段耗时如上图所示。

其中灰色部分是小程序底层的执行耗时,这块开发者是无法操控的。那在其他耗时中,下载代码包这块占比比较高。我们能怎么去减少这块耗时呢?

原先对课堂小程序的所有页面都是在一个包里面,那么这里我们采用分包方案。将主tab的3个页面以及util, 常用组件这种公共模块放在主包。其他每个页面单独分成300-500k左右大小对子包,子包可以引用主包对公共模块。

经过分包处理后,下载代码包对耗时减少了500ms左右,整体启动耗时降到了3.2s。整体来说,已经比小程序大盘平均启动耗时4.5s少了1.3s。

不过随着而来的,也有其他问题的引入,比如从首页打开课程详情页这一场景。

这个时候点击详情页时,需要先下载完详情页分包,才能打开课程详情页,显然这样的体验是极差的。

我们可以通过分包预加载的方案,来解决这个问题。打开首页,加载完主包后,可以静默加载其他分包,通过配置preloadRule即可实现分包预加载。

下面是一组本地测试数据,可以看到使用分包以及分包预加载的方案,可以减少启动耗时以及提高用户体验。

除了普通分包方案,小程序还有独立分包的方案。不依赖主包加载,即可打开分包页面。常用于一些比较独立的页面,比如活动页等。

但使用独立分包也有一些限制:

  • 独立分包无法引用主包或其他分包的资源
  • 全局App对象只能在主包定义,独立分包不能使用App对象
  • 生命周期只能通过:wx.onAppShow, wx.onAppHide来监听

解决了代码包下载的耗时以及采用分包,以及分包与加载提高页面打开性能以及效率。我们接下来看渲染耗时这块。

这是一个典型但小程序双线程通信的模型。每次调用setData方法,都会将数据从逻辑层传递到native层,再到渲染层,形成VD树进行渲染。

以上是setData传输数据量以及传输时间的关系图,可以看到当数据量大于64kb时,传输时间呈指数级增长。

因此,在使用setData时,应该尽量遵循以下建议:

  • 不要频繁调用setData, 尽量合并到一次setData调用
  • 传输数据量跟通信性能有关,尽量少于64k,避免一些不需要在页面展示的复杂数据结构或者长字符串
  • 与界面无关的数据最好不要设置在data中
  • 去掉不必要的事件绑定,减少通信的数据量以及次数
  • 不要在节点data前缀放置过大数据(需要传输target的currentTarget和dataset)

5,公共基础组件库

为了提高开发效率,代码复用率,我们对常见的一些能力以及功能型组件进行了封装(后续计划开源)。

这里拿基础能力的request组件来看,我们基于wx.request来封装,利用storage来存储登陆后的cookie信息,并在后续发起请求的时候,将登陆票据设置到请求头中。

采用可插拔插件式封装方法,来做各种插件到扩展。例如有loading插件,一个可以在发起请求的时候,自动显示loading,请求完成后,自动隐藏的插件。

以上就是小程序开发实践相关的分享。

四、QQ小程序

QQ小程序是一个基于手Q庞大流量,面向年轻化群体,跟随小程序行业标准的小程序平台。启动于18年12月份,并于6月底全量发布,目前覆盖微信小程序API达到了95%以上。

从用户侧来看,基本跟微信小程序类似。在聊天下拉即可发现小程序入口,里面有小程序商城,可发现各类小程序以及小游戏。它的开发者工具的UI也类似微信开发者工具。

它跟微信小程序之间有以下的一些区别:

API以及功能方面

  • 调用前缀:例如:qq.getSystemInfoSync (也兼容wx语法) ,覆盖率95%
  • webview: QQ小程序暂不支持webview
  • 唤起方式:支持http链接唤起小程序
  • 组件:不支持live-player, live-pusher组件
  • 分享:QQ小程序支持分享到QQ空间

开发者工具方面

  • 底层框架:都是基于nw.js
  • 编译能力:
    • 不支持增强型编译
    • 不支持多核心编译
  • 其他
    • 不支持体验评分
    • 不支持自动化测试

总的来说,QQ小程序的API基本对齐微信小程序,它的迭代速度较快,能力逐渐补齐中。并且拥有QQ生态流量红利,最重要的是从微信小程序迁移到QQ小程序工作量较小,代码95%以上基本可以复用。

总结

小程序生态发展之迅速,支付宝,百度等各大厂商都在各自研发自己的小程序。从开发者的角度来说,希望能够统一一套API规范,形成行业标准。前不久W3C中文兴趣组也在对小程序的生态进行了规范的相关讨论,相信后续必然会朝着标准化的方向发展。以上便是此次在线教育小程序开发实践之路的分享,可以通过下方的二维码关注IMWeb团队的公众号以及个人的公众号。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK