作者于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。
最后,我们选择了小程序原生框架作为我们的开发框架。并且补齐了跟其他开发框架对比欠缺的基础能力。当然,这里并非说其他框架不好,具体选择还是需要看具体的业务场景。4,目录规范
确定好开发框架后,统一的目录规范也是团队协同开发必须约束的。
在引入npm包管理后,我们在小程序的基础目录中,通过新起了一个miniprogram目录来作为小程序代码的根目录。这是由于小程序会对node_modules里面的包打包编译到miniprogram_npm目录,为了避免小程序的node_modules跟其他工程化相关的node_modules混在一起,才新起了一个文件夹来存放小程序工程代码。可以通过修改project.config.js可以配置小程序代码的根目录路径。
5,编码规范
约束好目录,那么在团队协同开发,如何维护规范化,风格统一的代码,我们希望可以团队成员开发时可以统一代码规范, 提交规范, 风格保持一致。因此,跟我们其他web项目一样,我们可以使用 eslint,stylelint,commitment,prettier等插件来对我们的代码进行约束,规范。通过git hook来在做提交时的校验检测,不通过则不允许提交。
通过Commitizen以及standard-version来自动化生成统一的版本号以及ChangeLog。会自动将你在本次版本迭代中,提交的规范化log(遵循Angular团队的commit规范: github.com/angular/ang… )自动生成ChangeLog, 注明是特性发布,bugfix还是breakingChange,以及对应的log信息。后续我们在需要回滚或者回溯某一版本的改动时,就可以一目了然。
我们基于上面的能力以及约束规范,做成统一的脚手架,方便团队在统一的环境下快速开发,并且开源了出去( github.com/imweb/gener… )。
三、小程序开发实践
介绍完我们的框架选型,工程化探索,接下去分享下在线教育小程序的开发实践经历。
1,小程序音视频
第一部分是小程序音视频能力相关的实践。腾讯课堂是一个在线学习的平台,那么最核心的就是音视频直播,录播能力。那么在小程序上面,我们如何搭建课堂音视频能力呢?1),直播场景
因此,我们可以使用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,降低了延迟。
介绍完直播接入方案,接着讲下录播。由于版权保护,腾讯课堂录播播放采用了加密HLS。
1,获取到加密HLS的m3u8地址,传给video;
2,浏览器video底层解析m3u8,发现其带有加密协议标识-EXT-X-KEY,其值是一个获取解密key的接口地址;
3,浏览器会自动发起该请求,发起请求,去获取解密key;
4,浏览器自动发起请求时,会把用户登陆态通过cookie方式带上,业务后台对cookie鉴权后返回解密key,之后浏览器拿到解密key后就可以解密播放了。
但在小程序中,由于小程序是没有cookie的,那么怎么去针对小程序发起的获取解密key请求鉴权呢?
补齐了音视频能力后,我们项目也正常上线。由于平台功能不断增加,小程序也在按照以下流程进行迭代发布。
揭晓下答案,主要有2个问题:
- 1,多人开发过程,npm包可能存在不同版本,比如登录能力的npm包,有可能会忘记更新最新包。
- 2,构建npm按钮在开发者工具上面入口比较隐蔽,容易导致更新了npm包但是忘记点击构建npm,覆盖了线上的特性 上面操作对于熟悉小程序开发的人来说不容易出错,但对于新人,由于不熟悉,容易疏忽。即使犯错但概率很小,但是也必须解决。
那么我们能否通过自动化工具来帮我们校验检测这些隐患呢?
1,代码合并主干检测
2,node_modules版本检测,必须是大于或者等于当前package.json的版本
3,自动执行构建npm操作
4,自动执行上传操作,包括填写版号以及备注信息其中1跟2可以通过githook以及npm命令来判断,3跟4涉及到小程序相关到能力调用,是否有暴露相关到接口可以调用呢?
1,进行是否更新最新主干代码检测;
2,判断是否安装了小程序开发者工具且正常设置到环境变量;
3,进行本地node_modules版本检测;
4,调用构建npm命令;
5,自动获取package.json的版本号作为上传版本,获取git 提交log作为备注; 6,调用上传命令进行上传
有了以上工具后,我们就可以愉快地进行开发迭代发布了。但随着我们课堂平台小程序的推广,课堂平台的各家机构都想拥有其自己的机构小程序,并且其页面是课堂平台小程序的一个子集。
通过分析后,我们决定通过构建的方式,从平台小程序中拆离出机构小程序代码。通过2份模版配置信息, 通过构建,可以动态生成平台小程序以及机构小程序的app.json。这样进行上传的时候,就只会上传对应的页面。代码复用的问题解决了,但随着而来还有另外一个问题。需要生成的机构有80多家,有些机构不一定有开发人员,如果帮助机构快速上传发布他们自己的机构小程序呢?
这里引入微信第三方平台的概念(open.weixin.qq.com/cgi-bin/sho… ),我们可以往微信开发平台申请成为第三方平台。机构申请完独立的小程序账号后,将其授权给我们腾讯课堂第三方平台。这样我们就可以获取到该机构到代码管理,版本发布到权限。通过上传我们之前构建好到机构小程序模版,再调用发布接口,就可以快速实现帮助机构发布其独立个体到机构小程序了。4,性能优化实践
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时,应该尽量遵循以下建议:
- 不要频繁调用setData, 尽量合并到一次setData调用
- 传输数据量跟通信性能有关,尽量少于64k,避免一些不需要在页面展示的复杂数据结构或者长字符串
- 与界面无关的数据最好不要设置在data中
- 去掉不必要的事件绑定,减少通信的数据量以及次数
- 不要在节点data前缀放置过大数据(需要传输target的currentTarget和dataset)
5,公共基础组件库
为了提高开发效率,代码复用率,我们对常见的一些能力以及功能型组件进行了封装(后续计划开源)。
这里拿基础能力的request组件来看,我们基于wx.request来封装,利用storage来存储登陆后的cookie信息,并在后续发起请求的时候,将登陆票据设置到请求头中。
采用可插拔插件式封装方法,来做各种插件到扩展。例如有loading插件,一个可以在发起请求的时候,自动显示loading,请求完成后,自动隐藏的插件。
以上就是小程序开发实践相关的分享。
四、QQ小程序
从用户侧来看,基本跟微信小程序类似。在聊天下拉即可发现小程序入口,里面有小程序商城,可发现各类小程序以及小游戏。它的开发者工具的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团队的公众号以及个人的公众号。
链接:https://juejin.im/post/5d15fc3be51d4510b71da637
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。