微前端实际应用:iframe、qiankun
多应用同时激活在线框架具备同时激活多应用,并保持这些应用路由同步能力组件式的使用方式无需注册,无需路由适配,在组件内使用,跟随组件装卸,卸载应用级别的keep-alive子应用开启保活模式,应用发生切换时整个子应用的状态可以先保存下来不丢失,结合预执行模式可以获得类似ssr的打开模式纯净无污染:利用iframe和ShadowRoot搭建js隔离沙箱和css隔离沙箱利用iframe的history和
目录
在上面的基础中了解到,目前常用的微前端实现方案有多种,其中目前常见使用的是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应用
-
在应用A中构造一个shadow和iframe,之后将应用B的html写入shadow中,js运行在iframe中。iframe的url:iframe保持和主应用同域且保留子应用的路径信息,这样可以使应用的js运行在iframe的location和history中来保证路由的正确性
-
在iframe中拦截document对象,统一将dom指向shadowRoot,此时新建的元素、弹窗等组件就可以正常的约束在shadowRoot的内部
b、解决iframe的三个缺点:
- dom割裂严重问题:主应用提供一个容器到shadowRoot插拔,shadowRoot内部的弹窗就可以覆盖到整个应用A上
- 路由状态丢失问题:浏览器的前进后退可以作用到iframe上,此时来监听iframe的路由变化并同步到主应用上,如果刷新浏览器,就可以从url读回保存的路由
- 通信非常困难问题:iframe和主应用是同域的,共享内存通信,且无界框架提供了一个去中心化事件机制
c、将上面的机制封装进wujie框架:
- 首次白屏问题,wujie实例可以提前实例化,包括shadowRoot、iframe的创建、js的执行,可以加快子应用第一次打开的时间
- 切换白屏问题:当wujie实例可以缓存下来,子应用的切换成本变的极低,如果采用保活模式,相当于shadowRoot的插拔
子应用完全独立的运行在iframe内,路由依赖iframe的location和history,可以在一张页面上同时激活多个子应用。因为iframe和主应用处于同一个top-level browsing context(顶级浏览上下文),所以浏览器前进、后退都可以作用到子应用
d、通过上面的方法实现无界方案
- 非常简单,使用没有任何心智负担
- 隔离完美,无论是js、css、dom都完全隔离开来
- 多应用激活,页面上可以摆放多个iframe来组合业务
- 通信
- 无白屏情况
- 路由不会丢失
1-3 使用无界
a、无界框架的基本使用步骤
使用例子,主应用为vue框架,使用的步骤为:
- 安装:
npm i @tencent/wujie-vue -S - 在主应用中引入:
import WujieVue from “@tencent/wujie-vue”; Vue.use(WujieVue); - 使用:
<WujieVue width="100%" height="100%" name="xxx" url="xxx" :sync="true" :fetch="fetch" :props="props" @xxx="handleXXX" ></WujieVue>
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微前端框架,即:将子项目的内容插入到主项目中呈现子项目的内容
- iframe方案
2-2 qiankun
a、基础知识
- qiankun是一个基于single-spa的微前端实现库,在此基础上实现开箱即用,使得子项目只需要很少的改动,就可以接入
- qiankun主要特征
- 基础single-spa封装,提供了更加开箱即用的API
- 技术栈无关,任何技术栈均可使用
- HTML Entry接入方式,使得接入微应用和iframe简单度相似
- 样式隔离,确保微应用之间样式互不干扰
- JS沙箱,确保微应用之间全局变量/事件 不冲突(JS沙箱代表:一块完全独立的区域,使用的都是自己独立的属性和方法)
- 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度
- umi插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统
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(<App />, 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、项目实战
此为学习总结,有错误的地方请指正 ~
更多推荐


所有评论(0)