iframe 接班人-微前端框架 qiankun 在中后台系统实践

背景

在转转的中台业务中,交易流转、业务运营和商户赋能等功能,主要集中在两个系统中(暂且命名为inner/outer)。两个系统基座(功能框架)类似,以 inner 系统为例,如图:

图片[1]-iframe 接班人-微前端框架 qiankun 在中后台系统实践-JieYingAI捷鹰AI

inner系统基座业务现状问题

维护迭代,随时间延续是不可避免的

至今,inner/outer均有以下特点:

初次接触上述问题时,闪现在脑海里的是:用iframe呀。确实,刚开始也是这样做的。

问题暴露,在维护迭代中是个契机

系统在一个长时间跨度的运行下,随着维护人员的变迁、使用人群的增多,更多的问题也接踵而至:

由于没有统一规范,每个功能模块在不同的开发者键盘下设想的结构不同,输出的风格也不统一,使整个系统看起来略显杂乱。

首先,iframe页面没有自己的历史记录,使用的是基座(父页面)的浏览历史。所以,当iframe页在内部进行跳转时,浏览器地址栏无变化,基座中加载的src资源也无变化,当浏览器刷新时,无法停留在iframe内部跳转后的页面上,需要用户重新走一遍操作,体验上会大打折扣。

iframe页产生的弹窗,一般只能遮罩iframe区域。

与基座非同源下,iframe无法直接获取基座url的参数,消息传递需要周转一下,如使用postmessage来实现;而动态创建的iframe页,或许还需要借助本地存储等。

iframe资源变更上线后,打开系统会发现iframe页依旧是老资源。需要用时间戳方案或强制刷新。

与基座非同源下,onerror事件无法使用。使用try catch解决此问题,尝试获取contentDocument时将抛出异常

以上问题,从业务价值看,对用户的使用体验会有损失;从工程价值看,希望能通过技术提升业务体验的同时,也提高系统的维护性。

改进实践 - 微前端

实践新技术,在问题暴露时是方向

大多数工程师,包括我,一边儿嘴里说着:学不动啦!一边儿想尝试一些新方式来优化系统。

结合问题分类,有思考一些尝试方向,如:

另外,大互联网时代,从工程角度看,社区对类似系统的探索有很多,除了iframe外,也有不少相对成熟的替代方案:

1. single-spa

2. qiankun

提起这两个,就要提一下微前端理念,目前社区有很多关于微前端架构的介绍,这里简单提一下:

Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently. — Micro Frontends

大致是说,微前端有以下特点:

技术栈无关:基座不限制子应用的技术栈

完全独立:子应用独立部署维护,接入时基座同步更新;又可独立运行

基于此,不难想到:iframe也是符合微前端理念的。那其他方案又是如何做的呢?

single-spa

社区里 single-spa 介绍也不少。根据 demo 比葫芦画瓢,可以知道它的架构分布:

图片[2]-iframe 接班人-微前端框架 qiankun 在中后台系统实践-JieYingAI捷鹰AI

single-spa架构

启动服务的配置主要是在single-spa-config文件中,包含项目名称、 项目地址、路由配置等:

// single-spa-config.js
import {registerApplication, start } from 'single-spa';

// 子应用唯一ID
const microAppName = 'react';

// 子应用入口
const loadingFunction = () => import('./react/app.js');

// url前缀校验
const activityFunction = location => location.pathname.startsWith('/react');

// 注册
registerApplication(
  microAppName,
  loadingFunction,
  activityFunction
);

//singleSpa 启动
start();

single-spa 让基座和子应用共用一个document,那就需要对子应用进行改造:把子项目的容器和生成的js插入到基座项目中。

<div id='micro-react'></div>
<script src=/js/chunk-vendors.js> </script>
<script src=/js/app.js> </script>

不过这种方式需要对现有项目的打包方式和配置项进行改造,成本很大。所以,对于已有的工程项目,我选择了放弃使用。

qiankun

qiankun 也是社区提到比较多的一个开源框架,是基于single-spa实现了开箱即用。可以采用html entry方式接入子应用,且子应用只需暴露一些生命周期,改动较少。【少】这个点,真是让我跃跃欲试。

目前我司业务场景是单实例模式(一个运行时只有一个子应用被激活),我们可以根据一张图来看看单实例下以html entry方式 qiankun 实现流程:

图片[3]-iframe 接班人-微前端框架 qiankun 在中后台系统实践-JieYingAI捷鹰AI

qiankun原理

如上图所示,一个子应用的全过程有:

具体实现细节,大家可以参考qiankun源码。

实践

从规范化开发角度,我司的中后台系统是基于 umi 开发(详细可参考我们之前的文章)。在构建主应用使用了配套的 qiankun 插件:@umijs/plugin-qiankun。

1. 初始化配置项,注册子应用

插件安装之后,我们可以在入口文件里配置:

此处主要以运行时为例

// app.js
export const qiankun = Promise.resolve().then(() => ({
  // 运行时注册子应用信息
  apps: [
    {
      // 结算单管理
      name: 'settlement'// 唯一id,与子应用的library 保持一致
      entry: '//xxx'// html entry
      history: 'hash'// 子应用的 history 配置,默认为当前主应用 history 配置
      container: '#root-content'// 子应用存放节点
      mountElementId: 'root-content' // 子应用存放节点
    }, {
      // 公告消息
      name: 'news'// 唯一id,与子应用的library 保持一致
      entry: '//xxx'// html entry
      history: 'hash'// 子应用的 history 配置,默认为当前主应用 history 配置
      container: '#root-content'// 子应用存放节点
      mountElementId: 'root-content' // 子应用存放节点
    }
  ],
  jsSandbox: { strictStyleIsolationtrue }, // 是否启用 js 沙箱,默认为 false
  prefetch: true// 是否启用 prefetch 特性,默认为 true
  lifeCycles: {
    // see https://github.com/umijs/qiankun#registermicroapps
    beforeLoad: (props) => {
      return Promise.resolve(props).then(() => loading())
    },
    afterMount(props) => {
      console.log('afterMount', props)
    },
    afterUnmount(props) => {
      console.log('afterUnmount', props)
    }
  }
}))

2. 装载子应用,在路由配置中使用microApp来获取相应的子应用名称:

// router.config.js
export default [
  {
    path'/',
    component'../layouts/BasicLayout',
    routes: [
      ...
      {
        path'/settlement/list',
        name'结算单管理',
        icon'RedEnvelopeOutlined',
        microApp'settlement',  // 子应用唯一id
      },
      {
        path'/settlement/detail/:id',
        name'结算单管理',
        icon'RedEnvelopeOutlined',
        microApp'settlement'// 子应用唯一id
        hideInMenu: true,
      },
      ...
      ...
      {
        component'./404',
      },
    ],
  },
  {
    component'./404',
  },
]

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
来说点什么吧!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容