乐趣区

关于前端:vivo-商品中台的可视化微前端实践

一、背景

在电商畛域内,商品是一个重要组成部分,与其对应的商品管理系统,则负责商品的新建、编辑、复制等性能。随着商品管理系统的成熟稳固和业务上的扩大需要,催化出了商品中台的诞生。它能够将现有商品性能最大效率的复用在很多业务上(公司内业务、公司外业务等)。而不是仅限于以后团队的业务应用。

在设计商品中台的前端零碎时,咱们应用了微前端和可视化技术,其能够达到如下成果:

  • 可视化技术能够让各个业务方的经营等相干人员,直观的看到其配置的数据在页面上的展现成果;
  • 微前端能够帮忙商品中台更快更好的适配到各个业务方的我的项目中。

至此,本篇文章的背景介绍结束,上面将会论述如何在商品中台前端零碎中做微前端和可视化。

二、可视化技术

目前商品中台的页面如下图所示:

图中左侧内容,就是商品可视化,它的外围能力如下:

  • 图中右侧所有的变动,都能在左侧失去实时更新和展现,如主图、sku 组合、价格、图文详情、商品参数等性能。
  • 图中左侧的可视化区域是一个规范的 h5 页面,能够把它看成一个子页面,它与外层的父页面在 ui 上是齐全隔离的,同时在数据上又是共享的。

上面我将会对可视化技术原理做残缺论述,请大家持续往下看。

三、可视化技术原理

可视化整体技术原理图如下:

从上图能够取得以下信息:

  • 子窗口用 iframe 展现;
  • 子窗口用 vuex 做状态治理;
  • 子窗口和父窗口通过共享状态(vue store)来实现数据通信。

看到这,小伙伴可能会有以下疑难:

iframe 和父窗口的数据通信是通过 postMessage 实现的,这里为什么不应用 postMessage 呢?

应用 vuex 实现 iframe 数据通信是如何实现的呢?

答复第一个疑难:为什么不应用 postMessage

实际过的小伙伴应该深有体会,应用 postMessage 的话,数据通信架构根本如下图所示:

联合上图能够剖析出 postMessage 有以下毛病:

  • 父窗口含有大量逻辑:父窗口须要将 vuex 的数据进行解决,而后通过 postMessage 进行传输;
  • 数据通信形式不纯正:vuex 和 postMessage 组合在一起,相互转换,使数据通信更加简单和难以管制;
  • 不反对 Vue.set , Vue.delete 等;
  • postMessage 只能同步字符串,不能 fn。

综合下面的毛病,在数据通信方面,没有应用 postMessage,而是应用 vuex 替换掉 postMessage,来实现 iframe 通信。

答复第二个疑难:应用 vuex 实现 iframe 数据通信是如何实现的呢?

这个问题的答案就是 uni-render。通过它,能够做到让子窗口通过 iframe 展现的同时,父子窗口共享 store。那这个 uni-render 是什么呢,能够持续往下读,将在下文给于第二个疑难的具体答复。

3.1 uni-render

uni-render 是一个让父子窗口能够不必 postMessage 就能共享 vue store 的技术计划。它蕴含以下要害内容:

  • 将 iframe 当成一个 dom 节点;
  • 父窗口渲染子窗口(iframe)裸露的组件;
  • 父子窗口共享 vue store;

uni-render 的技术原理图如下:

这里,我联合商品中台配置可视化区域做一个艰深解释:

  • 首先咱们把 vue 我的项目设置为多页利用,页面别离是商品预览页、商品治理页;
  • 其次,调整 vue 入口,每个页面对应一个入口;
  • 编写 iframe 组件和沙箱 vue;
  • 在商品治理页入口将沙箱 vue 和 store 挂载到 global 对象下;
  • 在商品预览入口将 global.parent 下的沙箱 vue 和 store 别离挂到 window 下和 global 下;
  • 最初,其余的内容依照 vue 多页写法失常编写即可。

通过上述 6 个步骤,就能够让用 iframe 做展现容器的商品预览页和商品治理页共享 store 啦。

这里,小伙伴可能会有疑难,为什么要应用沙箱 vue 呢?

这是因为 vue 的单例机制,子窗口(商品治理页)由父窗口(商品治理页)new Vue 渲染的,因而在子窗口中应用 use、filter、mixin、全局指令、全局组件等,会笼罩父窗口 vue 对象。所以须要隔离出一个洁净的和 vue 一样的 vue,而后用隔离出的沙箱 vue 来渲染子窗口(商品预览页)的内容。这样就能够 达到父子窗口的 vue 互不影响。

上面将介绍一些具体实现,如 iframe 组件、沙箱 vue、入口设计。iframe 组件的实现非常简单,如下图所示:

这个不再解释了。

沙箱 vue 的实现十分奇妙,如下图所示:

在 Function 上挂一个 $$clone 函数,这样 vue 下就会有 $$clone 函数,通过执行 Vue.$$clone(),将 vue 的各种属性挂载到 SandboxVue 上。同时返回 SandboxVue。即可失去一个洁净的沙箱 vue。

留神:这里的 vue 指的是 vue2,目前 vue3 不是单例机制,在 vue3 中是不须要沙箱 vue 的。vue 多页入口设计,如下图所示:

对应上文艰深解释 4、5 步骤。

至此,uni-render 技术计划论述完了。家喻户晓,大多数 h5、pc 建站的数据通信计划都绕不开 postMessage。而咱们通过 uni-render,让父窗口和 iframe 子窗口的数据通信不再须要 postMessage,同时只应用 vue 生态中的 vuex 做数据通信。这带来了十分多的益处,益处如下:

  • 对立数据通信计划;
  • 对 store 数据的 watch、computed、更加纯正,数据通信性能更加弱小;
  • 精简代码,和 postMessage 永恒辞别;
  • 反对同步函数,后方的路是星辰大海。

3.2 可视化总结

综上,商品中台的可视化介绍完了,咱们通过 uni-render 技术计划让商品预览页(iframe)和商品治理页的数据通信只通过 vuex 即可实现。让可视化的实时更新更加晦涩,可视化交互更加弱小。

介绍完可视化,上面我将持续介绍商品中台在微前端上的实际,请大家持续往下浏览。

四、商品中台微前端

这里咱们把商品中台设计成了微前端架构,使其可能齐全适应简单的内部业务。

这时,你可能会问,微前端是什么?

4.1 微前端是什么

概念如下 :多个小型利用聚合为一个利用供用户应用,每个小型利用能够独立开发、独立运行、独立部署,与技术栈无关。大家能够 把主利用设想成商场,那子利用就是商户,这样就好了解了。

留神:商品中台不是主利用,它是一个嵌入内部业务的子利用,不具备内部业务嵌入它自身。

微前端和一般的前端有什么区别呢?区别概括在下图中:

联合微前端概念,再浏览上图,能够感触到微前端所带来的劣势和价值。

4.2 为什么要做微前端

整体概括下,次要有以下两个目标:

  • 将商品中台更快、更好的嵌入到各个业务方我的项目中;
  • 为前面主利用的设计做筹备。

因而,咱们把商品中台我的项目设计成了微前端架构,它能够很好的解决前端中台化所面临的各种问题。晓得了目标,那么咱们是如何去设计微前端的呢?

五、商品中台微前端设计

目前微前端畛域最支流的技术计划有以下两种:

  • single-spa 技术计划;
  • iframe 技术计划;

基于这两种技术计划,业界产出一些成熟的框架,如 qiankun、qingtian(vivo 自研)等。设计架构如下简图所示:

上面将介绍商品中台应用 qiankun 框架设计的微前端架构的技术实现。

5.1 qiankun 方案设计架构

为什么应用 qiankun,最外围的起因是:在国内,应用最多的微前端框架就是 qiankun。整体成果也不错,所以咱们的中台须要设计 qiankun 技术架构来适配那些基于 qiankun 的业务。

在说设计架构前,先给大家介绍下 qiankun 的技术原理,如下图所示:

从图中能够晓得,qiankun 的外围在于创立微利用容器。理解技术外围后,上面开始介绍设计架构。设计架构如下图所示:

从图中能够晓得,次要有 8 块内容,上面将会顺次介绍这 8 块内容。

5.1.1  代码接入

主利用内注册微利用

{
  name: 'goods',
  entry: initEntry('goods'),
  container: '#root-view',
  render,
  // activeRule 作为辨别不同微利用的关键字
  activeRule: genActiveRule('/main/goods'),
  props: msg
}

微利用入口

微利用打包

5.1.2 接口跨域

解决接口跨域,次要有以下两种形式:

  • 主利用转发:接口的 host 与主利用统一,由主利用依据门路关键字 cmmdy 进行转发。
  • 微利用配置:微利用服务端配置容许跨域

这里咱们抉择了第一种形式,也就是主利用转发。

5.1.3 路由适配

这里须要留神的是:微利用 router 须要增加 baseUrl,并且要与主利用关键字 activeRule 保持一致。如下代码 (简写) 所示:

const KEY = 'product'
router = new VueRouter({
  mode: 'history',
  base: IN_CMS ? `/main/goods/${KEY}` : `/${KEY}`,
  routes
})

这个 KEY 变量就是关键字。

5.1.4 多页设置

目前多页设置的代码如下图所示:

每个页面作为一个独立的微利用引入,filename 设置与主利用 activeRule 值保持一致。

5.1.5 数据通信

思考一个问题,主利用与微利用之间如何通信?通信这块,次要有两种计划:

  • initGlobalState:也是运行时通信(官网计划);
  • window:挂载到 window 下。

initGlobalState 计划的优缺点如下:

长处:api 提供了数据的 change 事件,单方均能监听到数据变动。

毛病:微利用加载时,获取初始数据的机会太晚,不适宜用作微利用数据的初始化。

window 计划的优缺点如下:

长处:微利用代码全周期内均能够获取数据,很好的防止官网计划中获取数据太晚的问题。

毛病:须要本人解决对数据变动的监听。

商品中台采取的数据通信计划是联合了上述两种计划,相互舍短取长,都有应用。

5.1.6 环境辨别

次要有以下两种场景:

  • 辨别 qiankun 与非 qiankun 技术栈:应用 window.\_\_POWERED\_BY\_QIANKUN\_\_ 即可判断。
  • 辨别同样应用 qiankun 的不同主利用:主利用与微利用之间约定参数,通过 window 对象或者生命周期函数中的 props 对象传递,来进行判断。

5.1.7 本地联调

思考一个问题,本地没有主利用的服务,怎么实现主利用与微利用间的疾速联调?解决方案如下:

主利用注册微利用时,将 entry 设置为从 localstorage 中获取,在 localstorage 中手动批改入口 entry 的值为微服务的本地地址,就能够实现本地的联调。外围代码如下:

const timestamp = new Date().getTime()
const initEntry = (subSys) => {const LS_KEY_ENTRY = `__entry__${subSys}`
  const customEntry = localStorage.getItem(LS_KEY_ENTRY)
  if (customEntry) {return `${customEntry}`
  }
  if (subSys === 'goods') {return `//vshop-commodity.vivo.com.cn/goods/?t=${timestamp}`
  }
  return `${location.origin}/${subSys}/?t=${timestamp}`
}

通过上述代码,即可在主利用中对入口地址进行动静适配,达到灵便联调的目标。这块还能够将其做成配置核心的模式,这样就不必在 localstorage 中手动批改入口地址。

5.1.8 权限治理

这部分是属于业务强相干内容,做好顶层解耦即可,本文不再论述。

5.1.9 qiankun 设计架构总结

到此,商品中台的 qiankun 设计架构的核心内容论述完了,应用 qiankun 的过程中,也遇到了一些问题,但应用这种风行框架的益处就是,遇到问题时,能够去查阅相干文档和博客,基本上都能够找到相干的解决思路。基于 qiankun 的设计架构,体现出了不错的成果,也让商品中台可能以 signle-spa 的 技术计划嵌入到其余业务我的项目中。

5.2 踩坑教训分享

过程中遇到的坑较多,本文筛选几个踩坑教训分享进去。

5.2.1 uni-render 相遇 qiankun 跨域问题

景象:我的项目接入主利用,uni-render 管制的预览页面空白,控制台报跨域谬误。

起因:iframe 预览页面为商品中台域名,而子利用接入主利用后为主利用域名,从而导致跨域。

解决方案:主利用、子利用 html 入口文件头部设置 document.domain,使两者 domain 保持一致。

5.2.3 uni-render、qiankun、ueditor”化学反应“

问题一:

景象:qiankun 子利用中富文本组件 ueditor 性能异样。

起因:qiankun 对 ueditor 劫持,导致 ueditor 某些变量无奈获取到。

解决方案:在主利用中,通过 excludeAssetFilter 让 ueditor 的动态资源不要被 qiankun 劫持解决。

问题二:

景象:子利用中 ueditor 的申请 url 报错。

起因:ueditor 的申请 url 没加主利用申请前缀。

解决方案:子应用环境中,通过 ue.getActionUrl 给 ueditor 的申请 url 减少前缀。

问题三:

景象:子利用中 ueditor 单图上传失败。

起因:子利用设置了 domain,ueditor 的单图上传是通过 iframe 实现的,然而 iframe 没有设置 domain,导致上传失败。

解决方案:重写 ueditor 的单图上传,将 iframe 改为 xhr 上传。

至此,踩坑教训也分享完了,还有一些踩坑,这里就不再叙述了。在将几个技术交融在一起的过程中,总是会有一些料想不到的问题,正所谓兵来将挡、水来土掩,咱们用正确的心态去面对和解决这些问题即可。

六、总结

综上,咱们对商品中台的可视化和微前端做了整体的论述,蕴含以下内容:

  • 通过 uni-render 技术计划解决了可视化页面 iframe 和父页面的数据通信问题。
  • 通过 qiankun 解决了商品中台嵌入基于 single-spa 技术计划的内部业务。
  • uni-render 联合 qiankun 的踩坑教训。

在解决一个场景或者问题时,技术的实现细节不是最重要的,最重要的是脱离技术的 Principles。

最初用一句话结尾:Principles are higher than techniques. Principles produce techniques in an instant.

作者:vivo 互联网前端团队 -Yang Kun

退出移动版