目录
一、什么是微前端
二、主应用接入 qiankun
1.按照qiankun插件
2.注册微应用引用
3.挂载容器
三、微应用接入 qiankun
1.vite.config.ts
2.main.ts
ps:手动加载微应用方式
ps:为什么不用 iframe
一、什么是微前端
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。
微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。
微前端架构具备以下几个核心价值:
-
技术栈无关
主框架不限制接入应用的技术栈,微应用具备完全自主权 -
独立开发、独立部署
微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新 -
增量升级
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
-
独立运行时
每个微应用之间状态隔离,运行时状态不共享
二、主应用接入 qiankun
1.按照qiankun插件
yarn add qiankun
2.注册微应用引用
在入口文件main.js中添加如下代码:
import { registerMicroApps, start } from 'qiankun'
registerMicroApps(
[
{
name: 'micro-vue-1', // 必须与微应用注册名字相同
entry: 'http://localhost:5174', // 入口路径,开发时为微应用所启本地服务,上线时为微应用线上路径
container: '#micro-app-container', // 微应用挂载的节点
activeRule: '', // 当访问路由为 /micro-vue 时加载微应用
props: {
msg: '我是来自主应用的值-vue', // 主应用向微应用传递参数
},
},
// {
// name: 'react-app',
// entry: 'http://127.0.0.1:5175',
// container: '#react-app-container',
// activeRule: '/micro-react',
// props: {
// msg: '我是来自主应用的值-react',
// },
// },
]
// {
// // 生命周期钩子函数
// beforeLoad: (app) => {
// console.log('beforeLoad', app)
// },
// beforeMount: (app) => {
// console.log('beforeMount ', app)
// },
// afterMount: (app) => {
// console.log('afterMount', app)
// },
// beforeUnmount: (app) => {
// console.log('beforeUnmount ', app)
// },
// afterUnmount: (app) => {
// console.log('afterUnmount', app)
// },
// }
)
//step3 设置默认进入微应用
//setDefaultMountApp('/vue3')
start() //启动微应用
3.挂载容器
在需要嵌入的地方挂载容器
<div id="micro-app-container"></div>
三、微应用接入 qiankun
qiankun 暂不支持 Vite 方式接入,需安装 vite-plugin-qiankun
yarn add vite-plugin-qiankun
1.vite.config.ts
import { defineConfig } from 'vite'
import qiankun from 'vite-plugin-qiankun'
export default defineConfig((mode) => {
return {
plugins: [
qiankun('micro-vue-1', { // 微应用名字,与主应用注册的微应用名字保持一致
useDevMode: true,
}),
],
}
})
2.main.ts
import { createApp } from 'vue'
import App from './App.vue'
import {
renderWithQiankun,
qiankunWindow,
QiankunProps,
} from 'vite-plugin-qiankun/dist/helper'
const render = (props: QiankunProps = {}) => {
const { container } = props
const app: string | Element = container?.querySelector('#app') || '#app' // 避免 id 重复导致微应用挂载失败
createApp(App).mount(app)
}
const initQianKun = () => {
renderWithQiankun({
bootstrap() {
console.log('微应用:bootstrap')
},
mount(props) {
// 获取主应用传入数据
console.log('微应用:mount', props)
render(props)
},
unmount(props) {
console.log('微应用:unmount', props)
},
update(props) {
console.log('微应用:update', props)
},
})
}
qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render() // 判断是否使用 qiankun ,保证项目可以独立运行
ps:手动加载微应用方式
<template>
<button @click="loadApp">挂载微应用</button>
<button @click="unloadApp">卸载微应用</button>
<!-- 提供挂载容器 -->
<div id="sub-app-container"></div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { loadMicroApp } from 'qiankun'
let microApp: any = null // 微应用实例
const loadApp = () => {
if (microApp) return
microApp = loadMicroApp({
name: 'micro-vue-1', // 必须与微应用注册名字相同
entry: 'http://localhost:5174', // 入口路径,开发时为微应用所启本地服务,上线时为微应用线上路径
container: '#micro-app-container',
props: {
// 主应用向微应用传递参数
}
})
microApp.mountPromise.then(() => {
// 微应用加载完成后回调
})
}
const unloadApp = () => {
if (!microApp) return
microApp.unmount() // 卸载微应用
}
</script>
ps:为什么不用 iframe
为什么不用 iframe,这几乎是所有微前端方案第一个会被 challenge 的问题。但是大部分微前端方案又不约而同放弃了 iframe 方案,自然是有原因的,并不是为了 "炫技" 或者刻意追求 "特立独行"。
如果不考虑体验问题,iframe 几乎是最完美的微前端解决方案了。
iframe 最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。但他的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。
- url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
- UI 不同步,DOM 结构不共享。想象一下屏幕右下角 1/4 的 iframe 里来一个带遮罩层的弹框,同时我们要求这个弹框要浏览器居中显示,还要浏览器 resize 时自动居中..
- 全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
- 慢。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。