微前端--iframe集成方案

799 阅读2分钟

在之前的一篇文章中写了集中我用过的应用集成的方式,今天记录一下我在使用iframe集成方案的一些经验。

先说下优点:沙盒模式,各个子应用之前完全的独立的沙盒互不影响,不存样式、变量、依赖包等带来的问题;

缺点:跨域、通讯、独立的window窗口;

我们在使用iframe方案的时候。跨域主要是在服务端解决,比如nginx;通讯这部分开始制定好api,和带来的收益相比,维护成本还能接受;对于独window窗口带来的modal不居中、背景遮罩不全的问题,我们是舍弃了一部分体验的,这也是iframe集成方案最麻烦的一点;

我们在h5端也有尝试iframe的集成方案,也是因为历史债务问题,涉及到两个跨地区的款对,不得已选择了iframe方案,不过在维护和快速集成方面确实带来了很大的便利。

整体设计方案

路由

可以把每个子应用(iframe)封装成一个组件,切换路由是就是展示不同的组件。

这里有一个小技巧对应iframe来说,你可以把每个子应用都创建一个iframe,并且保持这个iframe不会被销毁,这样在下次进入子应用时,速度就很快了,只是改变一下iframe的url,并展示出来,在视觉上完全感受不到

举个例子(伪代码)

/**
 * 内存允许的话,每一个子应用都是一个单例,缓存下来iframe,这样第二次加载就很快
 */
function FinanceSingletonIframe() {
  // 控制iframe显示隐藏
  const [show, setShow] = useState(false)
  // 负责把父应用的路由转换成对应子应用的路由(iframe)
  const iframePath = {
    xxx: xxx
  }

  useEffect(() => {
    // 监听路由变化
    Router.onChange((router) => {
      // 根据条件判断显示隐藏
      if(['xxx', 'xxx'].indexOf(router.path) !== -1){
          setShow(true)
      }else{
        setShow(false)
      }
    })
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return (
    <div style={{display: show ? 'blank' : 'none'}}>
      <iframe
        ref={iframeRef}
        title="代账宝"
        style={getIframeStyle()}
        styleName="singleton-iframe"
        src={iframePath[router.path]}
      />
    </div>
  );
}

export default FinanceSingletonContent;

通讯

维护一个事件中心,这个方案可选的有很多,比如原生的api postmessage

下面是一个简单的实现

父应用声明一套api

cost fn = {}; 

// 注册事件 

function registerEvent(enentKey, fn){ fn[eventKey] = fn; } 

// 删除事件 

function unRegisterEvent(eventKey){ delete fn[eventKey] } 

// 获取事件 

function getEventFn(eventKey){ return fn[eventKey] }

// 调用事件 

function invokeEvent(eventKey, param){ fn[eventKey](param) } 

window.__EVENT_CENTER__ = {     
 registerEvent:registerEvent,    
 unRegisterEvent:unRegisterEvent,    
 getEventFn:getEventFn,    
 invokeEvent:invokeEvent
}

子应用

// 注册事件
window.top.__SERVYOU_DZB_H5__.registerEvent('test', () => {
    // todo
});
 
// 触发事件
window.top.__SERVYOU_DZB_H5__.invokeEvent('goBack', argumentsList);

然后再约定好api命名、参数怎么传就可以了

附一张h5的方案选型的对比图