vivo悟空活動中臺 - 微組件多端探索

本文首發於 vivo互聯網技術 微信公衆號
連接: mp.weixin.qq.com/s/oGX4XSm8F…
做者:悟空中臺研發團隊css

【悟空活動中臺】系列往期精彩文章:前端

1、背景

隨着小程序、快應用的用戶體驗愈來愈友好,用戶羣體龐大,運營小夥伴開始偏向將營銷活動投放至微信、支付寶、快應用等微應用中。git

小程序和快應用能夠比做更加「輕便」的應用,與傳統應用相比優勢是:體積小、加載快、無需安裝、精準觸達等。所以衆多企業都迫切但願在微應用的藍海里搶佔先機,獲取海量的渠道流量和優秀營銷效果。github

對於活動研發而言,各端小程序底層實現不一致,技術生態隔離,研發過程須要適配各平臺技術上差別。若是單純採用 case by case 的開發模式,學習成本高、適配週期長、技術風險點多,易產生太高的人力成本,難以知足運營快速搭建多樣化活動的訴求。web

基於上述痛點,咱們想借助悟空中臺的能力打通技術壁壘,實現小程序插拔式、可視化 、自適配各小程序平臺和快應用。帶着這個初心,開啓對悟空活動中臺多端改造之旅。vuex

2、多端場景技術挑戰

探索插拔式多端配置平臺,咱們首先梳理下技術難點:

一、企業級能力複用

悟空已經提供給運營和活動開發豐富的配套工具和解決方案,多端活動場景想要對運營和開發友好,必須在悟空能力上去擴充,畢竟傳統H5活動碰到的問題,多端活動場景也會遇到,咱們能夠站在巨人的肩膀上探索。

複用悟空活動中臺最大的挑戰是遵循workless工做流中的微前端架構方案,基於該方案的特色去擴展(組件熱插拔,子系統獨立部署)。

多端架構核心是利用平臺化手段沉澱複用已有技術能力,實現多端微組件熱插拔,一方面平臺可以適配多端組件,另外一方面多端組件的開發模式脫離於平臺 ,自成服務,這就須要探索是否有框架可以適應平臺化改造,實現高內聚,低耦合。

二、動態構建目標活動

目前,各個小程序的技術各不相同,舉個例子,咱們羅列下不一樣小程序和快應用核心 api 的使用方式。

由上表能夠比對出不一樣的小程序,快應用語法和 api 都不相同。這就意味着,同一個功能,開發者要與不一樣端一一對接,幾何倍的增長了開發的成本。

多端活動配置,基於提高配置效率的目的,必需要考慮實現自動化編譯不一樣目標程序,這就須要多端組件服務化,構建服務與組件服務解耦,根據配置動態拉去服務組件,遠程動態構建。

三、快應用的深度支撐

本次多端探索的重點是對快應用的快速支撐。快應用是由 11 家手機廠商聯合推出,投入流量超 10 億,同時在多家手機終端曝光導流。vivo 提供給快應用海量入口級資源曝光,包括負一屏、智慧場景、應用商店、瀏覽器等。

快應用的優點很明顯,如何利用快應用技術特色和核心能力,將傳統活動轉換成快應用活動是此次探索的重點,咱們但願能尋得鏈接悟空和快應用的橋樑。

3、尋找複用平臺能力最優解:多端框架

一、技術探索

悟空活動中臺前端技術選型爲vue,咱們須要對vue語法作DSL,來適配多端。基於該技術條件,咱們鎖定本次探索關鍵點:多端框架。

咱們先整理下思路:如何設計一個低耦合,高內聚多端框架?

歸納梳理後,設計分爲三個階段:

  1. DSL階段:建立一個 DSL 語法解釋器,並肯定一個語法對應解釋枚舉列表。
  2. AST階段:建立一個 AST 基礎語法樹,將DSL轉換成AST語法樹,再對AST進行transform,最後生成代碼。這個階段其實咱們都很熟悉,就是babel在編譯 ES6/7/8 的代碼時在作的事。換句話說,能夠藉助babel來節省轉換成本。
  3. AST轉換: 在AST基礎語法樹的transform規則以外進行擴展,內容主要是小程序和快應用端的轉換規則。

下面對這三個階段詳細說明:

1.一、對 vue 的 DSL

多端適用須要避免開發者操做原生DOM結構,所以須要抽象出一些基礎組件,來模擬div、ul等標籤 。咱們在AST的轉換過程當中須要去處理div,span等基礎Web DOM元素,替換爲自定義基礎組件。

1.二、根據不一樣小程序語法進行語法轉換

1.2.一、AST 是什麼

引用維基的描述:

在計算機科學中,抽象語法樹(Abstract Syntax Tree,AST),或簡稱語法樹(Syntax tree),是源代碼語法結構的一種抽象表示。它以樹狀的形式表現編程語言的語法結構,樹上的每一個節點都表示源代碼中的一種結構。之因此說語法是「抽象」的,是由於這裏的語法並不會表示出真實語法中出現的每一個細節。好比,嵌套括號被隱含在樹的結構中,並無以節點的形式呈現;而相似於 if-condition-then 這樣的條件跳轉語句,可使用帶有兩個分支的節點來表示。

大部分程序語言都經過 AST 把代碼轉換爲字節碼以便計算機執行,因爲JavaScript所處環境的特殊性(依託於瀏覽器,新語言特性依賴執行環境的支持,在瀏覽器暴露代碼,容易遭受攻擊),致使AST在JavaScript中擁有更多用武之地。

舉幾個栗子:

  • @babel/polyfill的做用是將代碼中的ES6語法轉化成 ES5 語法。
  • webpack的 UglifyJs 插件經常使用於代碼壓縮,混淆,美化等操做。

經過上述例子咱們發現AST經常使用於前端工具中,能夠無感知處理底層代碼轉換。

1.2.二、編譯vue文件

咱們可使用 vue-template-complier中的parseComponent 方法剝離 template、script、style ,並利用compile方法將template轉化爲對應的 AST,最終經過 @babel/parser解析 Javascript 以及css 代碼。

1.2.三、AST 轉換

AST的操做主要分爲三階段:

  • 將代碼轉化爲AST。
  • 對AST進行深度遍歷並轉換。
  • 將轉換後的AST轉回相應代碼。

以上步驟,咱們能夠利用@babel/parser,@babel/traverse,@babel/generator來處理。

多端適配工做,大體分爲如下幾個模塊:

  • 不一樣平臺 css 兼容,並對一些 css 兼容做降級處理。
  • 不一樣平臺 template兼容,好比<span> -> <text>,<div> -> <view>等等,這塊原則是基於上層DSL語義的規則並具有各端適用性。
  • 不一樣平臺 Javascript 兼容。在此階段咱們對這些語法糖進行適配處理,好比說window 或是document 等。

上述適配工做完成後,咱們須要將不一樣版本的AST轉換成多端適配代碼,再借助 loader生成不一樣端目錄結構。

經過對 babel,AST 的梳理,可以發現一個問題:開發多端框架,會產生相應的研發成本,後續框架的維護、擴展須要長期人力投入。

咱們真的須要去純手寫一個多端框架麼?下面是成熟開源多端框架研究梳理。

1.三、技術選型:各廠多端框架調研

截至到目前,已經有包括但不限於 Google,Facebook,阿里,騰訊,美團,京東,滴滴發佈了本身的開源多端通用框架,詳細清單以下

簡單對比:

從技術層面來講,Flutter屬於全包型,從底層引擎到中層DSL,到上層業務框架所有包含在裏面,這就從極大程度上保證了一套代碼多端渲染時的一致性。

RN和Weex嚴格來講不屬於多端通用框架,不能原生支持小程序端和快應用端。

京東出品的Taro框架是一套遵循 React 語法規範的多端開發解決方案。

最終從業務技術選型出發,咱們優先選擇了Dcloud團隊的uni-app。

1.3.一、uni-app

uni-app在設計思路上遵循經過轉義 view和viewModel代碼爲AST語法樹,並將AST轉化爲各終端匹配的代碼,完成多端的適配。

借用官方對該框架的描述:

uni-app 是一個使用 Vue.js 開發小程序、H五、App 的統一前端框架。開發者使用 Vue 語法編寫代碼,uni-app 框架將其編譯到 小程序(微信/支付寶/百度/字節跳動/QQ/釘釘)、App(iOS/Android)、H5 等多個平臺,保證其正確運行並達到優秀體驗。

uni-app 框架特色以下:

  • 完整的 vue 開發體驗。
  • 完全的組件化開發能力。
  • 完美支持vuex數據管理方案。

上述特色無縫與悟空技術棧對接,同時該框架支持多端發佈,能夠編譯成小程序、H5 等平臺代碼。

1.3.二、uni-app 對 vue 的改造

uni-app 做爲小程序和 vue 的中間層,在編譯和運行時對數據同步和事件代理作了改造,保證開發者使用 vue 語法開發就能對接不一樣端小程序。

數據同步:當組件觸發數據變化時,uni-app 修改了 initProperties 初始化屬性方法,在數組和對象遍歷元素數據,而且建立 observer 監聽 value 變化,將數據同步至小程序。

事件代理:uni-app 做爲中間層將不一樣小程序的事件轉換爲 vue 的事件,並支持大部分 web 事件。

原理上來講多端框架都是經過內嵌式DSL來實現。而後根據各端的差別性,使用一套 DSL 來描述,用多套AST轉換規則來支撐。

4、多端微組件動態構建目標活動

一、使用 uni-app 構造多端微組件

下面咱們經過步驟演示的方式,來演示經過 uni-app 開發一個微組件,以及平臺實現微組件動態渲染。

步驟一:本地 多端 SFC 組件

<template>
  <view>
    <image  :src="item.imgSrc" mode="aspectFill"></image>
  </view>
</template>
<script>
export default {
  props: ['item']
}
</script>

複製代碼
該多端SFC文件開發方式與普通 vue 的 SFC 組件相似,只是語法上遵循 uni 提供的組件和 api。

步驟二:編譯成 umd.js

如何將多端 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:

cross-env NODE_ENV=production UNI_PLATFORM=H5 vue-cli-service build --target lib --name code './src/plugin/code.vue'  --dest ./src/plugin/dist  --no-clean
複製代碼

步驟三:線上渲染

如何在動態組件的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>
複製代碼

微組件與普通微組件的顯著區別以下:

  • 多端微組件 api 與普通組件不一致。
  • 底層能力須要 uni 支撐。
  • 必須經過 mpType 在生命週期裏聲明渲染多端組件。

多端微組件的渲染特色是同時在一個頁面內渲染,須要頁面組件 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

咱們經過簡單的 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
}

複製代碼
最終展現下集成至平臺的簡單圖片組件:

5、快應用深度支撐

一、快應用基本特徵

快應用是基於手機硬件平臺的新型應用形態,標準是由主流手機廠商組成的快應用聯盟聯合制定的,以平臺化的生態模式對我的開發者和企業開發者全品類開放。

二、快應用核心能力及優點

爲了扶持快應用生態,賦能開發者,拓展場景將來,vivo 啓動「快應用百萬計劃」,面向廣大開發者開放申請。億級流量投入,聯合定製化扶持方案, 打造百萬級 DAU 行業標杆,共同建立完整健康的快應用生態。

vvivo 對快應用的投入和支持也是很是龐大的:

  • 系統層級添加桌面能力:保證留存
  • 分享,支付能力:支持第三方分享和支付
  • 語音場景支持:支持語音喚醒快應用
  • vivo 帳號打通能力:支持一鍵 vivo 帳號受權登 錄,可透傳手機號
  • URL 跳轉能力:任何渠道 CP 的 H5 頁面可拉起快應用
  • 添加負一屏卡片能力:快應用內可添加對應卡片至負一屏
  • POI 能力:根據地理位置提示服務

三、快應用深度定製

在此大前提下,悟空提供傳統手動開發快應用模式轉換爲自助快應用建站,以此來擴充 IOT,推廣活動,電商場景等玩法。

多端微組件至快應用小程序轉換流程:

多端微組件配置化專題後,咱們能夠選擇轉換不一樣的客戶端,而且 vivo 提供了小程序轉快應用的能力,轉換工具自己根據快應用標準,對邏輯層和代碼作了深層的定製,保證渲染速度和使用體驗。

6、探索成果演示

通過小夥伴們的共同努力以及 uni-app 的技術支撐,關鍵技術環境已所有打通,內部產品正在有條不紊的落地,靜待花開。下面 demo 展現下最終配置效果:

  • 基於悟空編輯器可視化能力,實現多端組件實時預覽,可視化配置
  • 多端編譯,可視化選擇將站點打包成小程序,快應用,支付寶,頭條小程序運行
  • 基於 uni-app 的組件開發模式,一套組件,運行多個平臺

對於活動的角色而言:

  • 開發者:實現了組件複用,遵循 vue 語法,無需知識遷移
  • 運營:上線多種形態的產品引流,增長投放的渠道
  • 產品:低成本拓展產品矩陣

7、開發多端微組件注意事項

uni-app 爲抹平不一樣小程序端的差別作了不少工做, 多端組件開發過程當中也有注意點:

  • 不能直接操做 dom,也不能使用 document、window、localstorage、cookie 等 ,只能經過 uni 提供的 api 完成
  • 原生 web 庫沒法支持,只能使用 uni 插件市場推薦的第三方庫
  • 開發時需儘可能規避邏輯層與視圖層分離帶來的通訊損耗
  • 如若是組件有特定客戶端的業務邏輯,可使用 uni 提供的特點條件編譯

8、寫在最後

經過本文對多端改造的介紹,相信你們已體驗多端微組件開發模式,並對多端活動配置平臺如何實現插拔式、自適配各小程序有必定的想法。

上述的探索只是悟空多端之路的開始,在豐富組件生態以及提供多端解決方案上,咱們還有很長的路要走,後續實踐出階段性成果也會分享給你們,歡迎一塊兒溝通討論。

更多內容敬請關注 vivo 互聯網技術 微信公衆號

注:轉載文章請先與微信號:Labs2020 聯繫

相關文章
相關標籤/搜索