您好,登录后才能下订单哦!
本文首发于 vivo互联网技术 微信公众号
链接: https://mp.weixin.qq.com/s/oGX4XSm8F4fa1ocLdpyqlA
作者:悟空中台研发团队
【悟空活动中台】系列往期精彩文章:
《 揭秘 vivo 如何打造千万级 DAU 活动中台 - 启航篇》 主要为大家讲述 vivo 活动中台的能力与创新。
《 悟空活动中台 - 微组件状态管理(上)》介绍了活动页内 RSC 组件之间的状态管理和背后的设计思路。
《 悟空活动中台 - 微组件状态管理(下)》探索平台和跨沙箱环境下的微组件状态管理。
《 vivo 悟空活动中台-基于行为预设的动态布局方案》本文以“满屏”场景下的页面布局思考为切入点,以微组件为元素单元,提供了一种新的布局方案设计思路——基于行为预设的动态布局方案,并详细的分享了设计目的及具体实现方案。
随着小程序、快应用的用户体验越来越友好,用户群体庞大,运营小伙伴开始偏向将营销活动投放至微信、支付宝、快应用等微应用中。
小程序和快应用可以比作更加“轻便”的应用,与传统应用相比优点是:体积小、加载快、无需安装、精准触达等。因此众多企业都迫切希望在微应用的蓝海里 抢占先机,获取海量的渠道流量和优秀营销效果。
对于活动研发而言,各端小程序底层实现不一致,技术生态隔离,研发过程需要适配各平台技术上差异。如果单纯采用 case by case 的开发模式,学习成本高、适配周期长、技术风险点多,易产生过高的人力成本,难以满足运营快速搭建多样化活动的诉求。
基于上述痛点,我们想借助悟空中台的能力打通技术壁垒,实现小程序 插拔式、可视化 、自适配各小程序平台和快应用。带着这个初心,开启对悟空活动中台多端改造之旅。
探索插拔式多端配置平台,我们首先梳理下技术难点:
悟空已经提供给运营和活动开发丰富的配套工具和解决方案,多端活动场景想要对运营和开发友好,必须在悟空能力上去扩充,毕竟传统H5活动碰到的问题,多端活动场景也会遇到,我们可以站在巨人的肩膀上探索。
复用悟空活动中台最大的挑战是遵循workless工作流中的微前端架构方案,基于该方案的特点去扩展(组件热插拔,子系统独立部署)。
多端架构核心是利用平台化手段沉淀复用已有技术能力,实现多端微组件热插拔,一方面平台能够适配多端组件,另一方面多端组件的开发模式脱离于平台 ,自成服务,这就需要探索是否有框架能够适应平台化改造,实现高内聚,低耦合。
目前,各个小程序的技术各不相同,举个例子,我们罗列下不同小程序和快应用核心 api 的使用方式。
由上表可以比对出不同的小程序,快应用语法和 api 都不相同。这就意味着,同一个功能,开发者要与不同端一一对接,几何倍的增加了开发的成本。
多端活动配置,基于提升配置效率的目的,必须要考虑实现自动化编译不同目标程序,这就需要多端组件服务化,构建服务与组件服务解耦,根据配置动态拉去服务组件,远程动态构建。
本次多端探索的重点是对快应用的快速支撑。快应用是由 11 家手机厂商联合推出,投入流量超 10 亿,同时在多家手机终端曝光导流。vivo 提供给快应用海量入口级资源曝光,包括负一屏、智慧场景、应用商店、浏览器等。
快应用的优势很明显,如何利用快应用技术特点和核心能力,将传统活动转换成快应用活动是这次探索的重点,我们希望能寻得连接悟空和快应用的桥梁。
悟空活动中台前端技术选型为vue,我们需要对vue语法做DSL,来适配多端。基于该技术条件,我们锁定本次探索关键点:多端框架。
我们先整理下思路:如何设计一个低耦合,高内聚多端框架?
概括梳理后,设计分为三个阶段:
下面对这三个阶段详细说明:
多端适用需要避免开发者操作原生DOM结构,因此需要抽象出一些基础组件,来模拟div、ul等标签 。我们在AST的转换过程中需要去处理div,span等基础Web DOM元素,替换为自定义基础组件。
引用维基的描述:
在计算机科学中,抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。之所以说语法是“抽象”的,是因为这里的语法并不会表示出真实语法中出现的每个细节。比如,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现;而类似于 if-condition-then 这样的条件跳转语句,可以使用带有两个分支的节点来表示。
大部分程序语言都通过 AST 把代码转换为字节码以便计算机执行,由于JavaScript所处环境的特殊性( 依托于浏览器,新语言特性依赖执行环境的支持,在浏览器暴露代码,容易遭受攻击),导致AST在JavaScript中拥有更多用武之地。
举几个栗子:
通过上述例子我们发现AST常用于前端工具中,可以无感知处理底层代码转换。
我们可以使用 vue-template-complier中的parseComponent 方法剥离 template、script、style ,并利用compile方法将template转化为对应的 AST,最终通过 @babel/parser解析 Javascript 以及css 代码。
AST的操作主要分为三阶段:
以上步骤,我们可以利用@babel/parser,@babel/traverse,@babel/generator来处理。
多端适配工作,大致分为以下几个模块:
上述适配工作完成后,我们需要将不同版本的AST转换成多端适配代码,再借助 loader生成不同端目录结构。
通过对 babel,AST 的梳理,能够发现一个问题:开发多端框架,会产生相应的研发成本,后续框架的维护、扩展需要长期人力投入。
我们真的需要去纯手写一个多端框架么?下面是成熟开源多端框架研究梳理。
截至到目前,已经有包括但不限于 Google,Facebook,阿里,腾讯,美团,京东,滴滴发布了自己的开源多端通用框架, 详细清单如下:
简单对比:
从技术层面来说,Flutter属于全包型,从底层引擎到中层DSL,到上层业务框架全部包含在里面,这就从极大程度上保证了一套代码多端渲染时的一致性。
RN和Weex严格来说不属于多端通用框架,不能原生支持小程序端和快应用端。
京东出品的Taro框架是一套遵循 React 语法规范的多端开发解决方案。
最终从业务技术选型出发,我们优先选择了Dcloud团队的uni-app。
uni-app在设计思路上遵循通过转义 view和viewModel代码为AST语法树,并将AST转化为各终端匹配的代码,完成多端的适配。
借用官方对该框架的描述:
uni-app 是一个使用 Vue.js 开发小程序、H5、App 的统一前端框架。开发者使用 Vue 语法编写代码,uni-app 框架将其编译到 小程序(微信/支付宝/百度/字节跳动/QQ/钉钉)、App(iOS/Android)、H5 等多个平台,保证其正确运行并达到优秀体验。
uni-app 框架特点如下:
上述特点无缝与悟空技术栈对接,同时该框架支持多端发布,可以编译成小程序、H5 等平台代码。
uni-app 作为小程序和 vue 的中间层,在编译和运行时对 数据同步和事件代理做了改造,保证开发者使用 vue 语法开发就能对接不同端小程序。
数据同步:当组件触发数据变化时,uni-app 修改了 initProperties 初始化属性方法,在数组和对象遍历元素数据,并且创建 observer 监听 value 变化,将数据同步至小程序。
事件代理:uni-app 作为中间层将不同小程序的事件转换为 vue 的事件,并支持大部分 web 事件。
原理上来说多端框架都是通过内嵌式DSL来实现。然后根据各端的差异性,使用一套 DSL 来描述,用多套AST转换规则来支撑。
下面我们通过步骤演示的方式,来演示通过 uni-app 开发一个微组件,以及平台实现微组件动态渲染。
该多端SFC文件开发方式与普通 vue 的 SFC 组件类似,只是语法上遵循 uni 提供的组件和 api。
如何将多端 SFC 组件编译成 umd 文件?
cli 脚手架支持采用@vue/cli+@dcloudio/vue-cli-plugin-uniUNI_PLATFORM 的方式,根据参数自定义目标小程序的 umd. js 文件, 并且还可以通过 cli 自定义编译平台:
{ /** package.json其它原有配置 */ "uni-app": { // 扩展配置 "scripts": { "custom-platform": { //自定义编译平台配置,可通过cli方式调用 "title": "自定义扩展名称", // 在HBuilderX中会显示在 运行/发行 菜单中 "BROWSER": "", //运行到的目标浏览器,仅当UNI_PLATFORM为H5时有效 "env": { //环境变量 "UNI_PLATFORM": "" //基准平台 }, "define": { //自定义条件编译 "CUSTOM-CONST": true //自定义条件编译常量,建议为大写 } } } }
uni 脚手架集成 vue-cli-service 构建方式,生成 componet.umd.min.js:
如何在动态组件的umd.js中的组件对象导出并在web端使用呢?首先看下多端的 umd.js:
;(function(e, t) { 'object' === typeof exports && 'object' === typeof module ? (module.exports = t()) : 'function' === typeof define && define.amd ? define([], t) : 'object' === typeof exports ? (exports['code'] = t()) : (e['code'] = t()) })('undefined' !== typeof self ? self : this, function() { return (function(e) { var t = {} ... ... ... })['default']
代码的形式与普通微组件转换为 umd.js 是一致的,所以 plugin 组件渲染的方式也是通过 vue 自带 component 动态组件来渲染。
<template> <div> <component :is="mode" v-if="mode"></component> </div> </template> <script> export default { data() { return { mode: null }; }, methods: { async load() { ... //此时内部的self变量,被外部变量mode代替,成功将组件对象导出 new Function("self", `return ${await data.text()}`)(mode); this.mode = mode.code; ... } } }; </script>
微组件与普通微组件的显著区别如下:
多端微组件的渲染特点是同时在一个页面内渲染,需要页面组件 page-index 遍历组件直接渲染到 view 中:
按照平台开发规范,一个标准的微组件结构是这样:
├── code.vue # 编辑器中渲染的UI组件 ├── prop.vue # 属性面板中渲染的配置组件 ├── setting.json # 存储初始化基础配置和业务配置 └── package.json # 依赖信息
在平台服务中,H5 设计器中配置面板prop.vue运行的 H5 环境,而多端组件code.vue运行在页面设计区。
在 H5 编辑器设计上,我们采用独立的沙箱环境,设计区和平台环境相互解耦,多端微组件复用 H5 专题页(组件与组件之间),平台的编辑器环境(组件和平台之间)。
这种设计可以解决如下问题:
微组件的数据是围绕着 item 去变化的,code.vue 只需要遵循 vue 单文件组件的开发规则,以及使用 uni 提供组件去开发,极大的降低了组件的开发门槛,最终 code.vue 平台会使用 uni/cli 直接编译成 UMD 文件,运行至编辑器的沙箱环境中,完全复用组件之间数据传递的规则,具体的运行逻辑图见:
多端微组件完全遵循 vue 语法,无需太多学习成本,如果看懂了上述开发流程以及运行方式,那么恭喜,你已经掌握了多端改造的精髓。
多端微组件与常规微组件的业务流程是一致的,最终通过不同的组件搭配和数据配置,生成符合运营预期的专题,发布后生成站点。
值得注意的是:微组件通过 node 服务下发,可以自定义初始脚手架,构建命令,多端微组件基于该特点以及普通微组件建 H5 应用的方式,将 uni 脚手架作为站点底层脚手架,动态拉取站点配置的多端微组件,最终根据动态修改 UNI_PLATFORM 构建命令生成目标小程序代码包。
上图解释了整个站点构建流程,可以看到多端服务组件配合远程脚手架可以根据不同的构建命令生成对应平台的应用资源包。
我们通过简单的 demo 体验下多端微组件开发模式。
以下展示最高频率使用的图片组件为列,code.vue 单文件组件可以使用 vue 语法直接开发。
<!-- template语法,直接使用image标签 --> <template> <image :style="style" :src="item.imgSrc" mode="aspectFill"></image> </template> <script> export default { //item为配置数据,prop数据修改item通过vuex直接同步至code props: ['item'], computed: { style() { //根据item数据设置图片大小 let style = {} style.width = this.item.width style.height = this.item.width/this.item.vivo_scale return style } } } </script>
配置侧 prop.vue 只需要展示图片的链接地址,让运营实时配置、修改图片链接。
prop 配置侧运行在 pc 端,无需使用 uni 语法,遵循传 vue 单文件开发规范。
<template> <el-form label-width="70px" :model="item" class="vivo-hot-config"> <el-form-item label="素材图片"> <media-picker :defaultSelect="item.imgSrc" @select-change="selectImg"></media-picker> <div class="jy-size">建议上传50KB以内图片</div> </el-form-item> </el-form> </template> <script> import MediaPicker from '@wukong/mediaPicker' export default { components: { MediaPicker }, name: '', props: ['item'], methods: { selectImg(img) { if (img.mediaPath) { this.item.imgSrc = img.mediaPath image.onload = () => { this.item.vivo_scale = image.width / image.height } } else { this.item.imgUrl = '' } } } } </script> </style>
其中MediaPicker是平台给开发者提供的媒体库内置组件,用来连接开发者与平台,开发者根据内置的 api 就可以获取平台素材库能力。
对于配置数据prop.vue,沿用原有构建逻辑,而 code.vue 则是用 uni 语法开发,最终通过 uni+vue 打包方式,生成 code.umd.min.js。
初始化的配置参数只需要声明图片的配置:长、宽、链接。
{ "imgSrc": "https://www.baidu.com/img/bd_logo1.png", "height": 320, "vivo_scale": 1 }[object Object]
最终展示下集成至平台的简单图片组件:
(查看 原图请点击原文链接 )
快应用是基于手机硬件平台的新型应用形态,标准是由主流手机厂商组成的快应用联盟联合制定的,以平台化的生态模式对个人开发者和企业开发者全品类开放。
为了扶持快应用生态,赋能开发者,拓展场景未来,vivo 启动“快应用百万计划”,面向广大开发者开放申请。亿级流量投入,联合定制化扶持方案, 打造百万级 DAU 行业标杆,共同创建完整健康的快应用生态。
vvivo 对快应用的投入和支持也是非常庞大的:
在此大前提下,悟空提供传统手动开发快应用模式转换为自助快应用建站,以此来扩充 IOT,推广活动,电商场景等玩法。
多端微组件至快应用小程序转换流程:
多端微组件配置化专题后,我们可以选择转换不同的客户端,并且 vivo 提供了小程序转快应用的能力,转换工具本身根据快应用标准,对逻辑层和代码做了深层的定制,保证渲染速度和使用体验。
经过小伙伴们的共同努力以及 uni-app 的技术支撑,关键技术环境已全部打通,内部产品正在有条不紊的落地,静待花开。下面 demo 展示下最终配置效果:
(查看 原图请点击原文链接 )
对于活动的角色而言:
uni-app 为抹平不同小程序端的差异做了很多工作, 多端组件开发过程中也有注意点:
通过本文对多端改造的介绍,相信大家已体验多端微组件开发模式,并对多端活动配置平台如何实现插拔式、自适配各小程序有一定的想法。
上述的探索只是悟空多端之路的开始,在丰富组件生态以及提供多端解决方案上,我们还有很长的路要走,后续实践出阶段性成果也会分享给大家,欢迎一起沟通讨论。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。