微前端实际应用:iframe、qiankun

目录

1、iframe

1-1 iframe基本理解

1-2 无界方案

1-3 使用无界

1-4 实现细节

1-5 无界微前端框架总结

2、qiankun

2-1 微前端知识温故

2-2 qiankun


在上面的基础中了解到,目前常用的微前端实现方案有多种,其中目前常见使用的是qiankun,以前常用的框架是iframe的微前端方案,下面我们先来学习一下之前的框架iframe实现微前端方案

1、iframe

1-1 iframe基本理解

  • 在之前使用iframe的时候,是在页面的使用中引入另外一个页面进行渲染,所以它的基本功能是:在一个web应用中独立的运行另一个web应用
  • iframe的使用优点
    • 简单:使用简单
    • 隔离完美:js,css,dom完全隔离
    • 多应用激活:可以在页面上使用多个iframe来组合业务
  • iframe的使用缺点
    • 路由状态丢失:刷新一下之后,iframe的url状态会丢失
    • dom割裂严重:弹窗只能在iframe内部展示,无法覆盖全局
    • 通信困难:通过postmessage传递序列化的信息
    • 白屏时间长:加载时间长导致页面白屏,对于SPA应用来说此弊端太大

1-2 无界方案

  • 综合上面的优缺点,我们一般会想保留优点去掉缺点,无界方案正好是此方案的解法

a、例子:假设有A应用,想加载B应用

  • 微前端实际应用:iframe、qiankun_第1张图片

    在应用A中构造一个shadow和iframe,之后将应用B的html写入shadow中,js运行在iframe中。iframe的url:iframe保持和主应用同域且保留子应用的路径信息,这样可以使应用的js运行在iframe的location和history中来保证路由的正确性
  • 微前端实际应用:iframe、qiankun_第2张图片

    在iframe中拦截document对象,统一将dom指向shadowRoot,此时新建的元素、弹窗等组件就可以正常的约束在shadowRoot的内部

b、解决iframe的三个缺点:

微前端实际应用:iframe、qiankun_第3张图片
  • dom割裂严重问题:主应用提供一个容器到shadowRoot插拔,shadowRoot内部的弹窗就可以覆盖到整个应用A上
  • 路由状态丢失问题:浏览器的前进后退可以作用到iframe上,此时来监听iframe的路由变化并同步到主应用上,如果刷新浏览器,就可以从url读回保存的路由
  • 通信非常困难问题:iframe和主应用是同域的,共享内存通信,且无界框架提供了一个去中心化事件机制

c、将上面的机制封装进wujie框架:

微前端实际应用:iframe、qiankun_第4张图片
  • 首次白屏问题,wujie实例可以提前实例化,包括shadowRoot、iframe的创建、js的执行,可以加快子应用第一次打开的时间
  • 切换白屏问题:当wujie实例可以缓存下来,子应用的切换成本变的极低,如果采用保活模式,相当于shadowRoot的插拔
微前端实际应用:iframe、qiankun_第5张图片

子应用完全独立的运行在iframe内,路由依赖iframe的location和history,可以在一张页面上同时激活多个子应用。因为iframe和主应用处于同一个top-level browsing context(顶级浏览上下文),所以浏览器前进、后退都可以作用到子应用

d、通过上面的方法实现无界方案

  • 非常简单,使用没有任何心智负担
  • 隔离完美,无论是js、css、dom都完全隔离开来
  • 多应用激活,页面上可以摆放多个iframe来组合业务
  • 通信
  • 无白屏情况
  • 路由不会丢失

1-3 使用无界

a、无界框架的基本使用步骤

使用例子,主应用为vue框架,使用的步骤为:

  1. 安装:
    npm i @tencent/wujie-vue -S
  2. 在主应用中引入:
    import WujieVue from “@tencent/wujie-vue”; Vue.use(WujieVue);
  3. 使用:

b、主子应用中无界的使用区别

  • 在主应用中不需要做任何改造
  • 在子应用中:
    • 开放跨域配置,因为子应用是在主应用域内请求和运行的
    • 对webpack应用,修改动态加载路径
    • 当子应用保活模式无需进一步的修改,非保活模式需要将实例挂载到无界声明周期内
if (window.__POWERED_BY_WUJIE__) {
  let instance;
  window.__WUJIE_MOUNT = () => {
    instance = new Vue({ router, render: (h) => h(App) }).$mount("#app");
  };
  window.__WUJIE_UNMOUNT = () => {
    instance.$destroy();
  };
} else {
  new Vue({ router, render: (h) => h(App) }).$mount("#app");
}

1-4 实现细节

实现细节部分看链接:基于 iframe 的全新微前端方案 - 腾讯云开发者社区-腾讯云

1-5 无界微前端框架总结

无界框架的优点:

  • 多应用同时激活在线框架具备同时激活多应用,并保持这些应用路由同步能力
  • 组件式的使用方式无需注册,无需路由适配,在组件内使用,跟随组件装卸,卸载
  • 应用级别的keep-alive子应用开启保活模式,应用发生切换时整个子应用的状态可以先保存下来不丢失,结合预执行模式可以获得类似ssr的打开模式
  • 纯净无污染
    • 利用iframe和ShadowRoot搭建js隔离沙箱和css隔离沙箱
    • 利用iframe的history和主应用的history在同一个top-level browsing context来搭建天然的路由同步机制
  • 性能和体积兼具
  • 开箱即用,样式的兼容、路由的处理、弹窗的处理、热更新的加载,子应用完成接入即可开箱即用无需额外处理,使得应用接入成本降低

无界框架的缺点:

  • 内存占用高,在使用时我们为了降低子应用白屏时间,将未激活应用的shadowRoot和iframe常驻内存并且保活模式下每张页面都需要独占一个wujie实例,内存开销较大
  • 兼容性一般,目前使用的浏览器shadowRoot和proxy能力,但是没有做降级方案
  • 某些第三方库无法兼容导致穿透,iframe劫持document到shadowRoot时,某些第三方库可能无法兼容导致穿透

2、qiankun

下面我们来学习qiankun的微前端框架,学习链接

2-1 微前端知识温故

  • 微前端是一种多个团队通过独立发布功能的方式来共同构建现代化web应用的技术手段及方法策略
  • 微前端的诞生主要为了解决如下两个问题
    • 复用(嵌入)别人的项目页面,且别人的项目运行在他自己的环境上
    • 将原先一个巨无霸应用拆分一个个的小项目,这些小项目既可以独立开发部署,又可以自由组合
  • 微前端的好处
    • 技术无关
    • 快速打包,独立部署,互不影响
    • 可以很方便的复用已有的功能模块,避免重复开发
  • 微前端的主要解决方案
    • iframe方案
      • 特点是提供了浏览器原生硬隔离方案,解决了样式隔离,js隔离的问题
      • 问题:隔离性无法被突破,导致应用间上下文无法被共享(本地存储/全局变量/公共插件),两个项目不同源(跨域)情况下数据传输需要依赖postMessage,导致一系列的开发体验问题
    • single-spa方案
      • 此框架上手不简单,开发部署需要修改大量的webpack的配置,且对子项目的改造也很多
      • 此框架让父子项目属于同一个document,好处:数据、文件和公共插件可以共享;缺点js/css污染
      • 将多个单页面应用聚合为一个整体应用的JS微前端框架,即:将子项目的内容插入到主项目中呈现子项目的内容

2-2 qiankun

a、基础知识

  • qiankun是一个基于single-spa的微前端实现库,在此基础上实现开箱即用,使得子项目只需要很少的改动,就可以接入
  • qiankun主要特征
    • 基础single-spa封装,提供了更加开箱即用的API
    • 技术栈无关,任何技术栈均可使用
    • HTML Entry接入方式,使得接入微应用和iframe简单度相似
    • 样式隔离,确保微应用之间样式互不干扰
    • JS沙箱,确保微应用之间全局变量/事件 不冲突(JS沙箱代表:一块完全独立的区域,使用的都是自己独立的属性和方法)
    • 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度
    • umi插件,提供了 @umijs/plugin-qiankunumi 应用一键切换成微前端架构系统

b、快速开发使用步骤

主应用中:

主应用不限技术栈,只需要提供一个容器DOM,然后注册微应用再start即可

  • 安装:npm i qiankun -S 或 yarn add qiankun

主应用中注册微应用

方法1:微前端与路由关联

import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'react app', // app name registered
    entry: '//localhost:7100',
    container: '#yourContainer',
    activeRule: '/yourActiveRule',
  },
  {
    name: 'vue app',
    entry: { scripts: ['//localhost:7100/main.js'] },
    container: '#yourContainer2',
    activeRule: '/yourActiveRule2',
  },
]);

start();

微应用信息注册完之后,浏览器的url发生变化,便会自动触发qiankun的匹配逻辑,所有activeRule规则匹配的微应用就会被插到指定的container中,同时依次调用微前端暴露出的生命周期钩子

方法2:微前端与路由无关联

微前端不直接与路由关联时,可以手动加载微前端

import { loadMicroApp } from 'qiankun';

loadMicroApp({
  name: 'app',
  entry: '//localhost:7100',
  container: '#yourContainer',
});

微应用中:

微应用不需要额外安装任何其他依赖即可接入qiankun主应用

a、导出相应的生命周期钩子

微应用需要在自己的入口js(即:配置的webpack的entry.js)导出bootstrap、mount、unmount三个生命周期钩子,来供主应用在适当的时机调用

/**
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap() {
  console.log('react app bootstraped');
}

/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props) {
  ReactDOM.render(, props.container ? props.container.querySelector('#root') : document.getElementById('root'));
}

/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount(props) {
  ReactDOM.unmountComponentAtNode(
    props.container ? props.container.querySelector('#root') : document.getElementById('root'),
  );
}

/**
 * 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
 */
export async function update(props) {
  console.log('update props', props);
}

b、配置微应用的打包工具

代码暴露出相应的声明周期钩子之外,为了让主应用可以正确的识别微应用暴露出来的一些信息,微前端的打包工具webpack增加如下配置

const packageName = require('./package.json').name;

module.exports = {
  output: {
    library: `${packageName}-[name]`,
    libraryTarget: 'umd',
    jsonpFunction: `webpackJsonp_${packageName}`,
  },
};

c、项目实战

此为学习总结,有错误的地方请指正 ~

你可能感兴趣的:(微前端,前端)