应用场景: 1. 主应用与多个相互独自的微应用 一起构成了整个大的微前端应用
2. 可以在同一个页面中,加载多个不同的微应用,每个微应用都是主应用的组成部分 或者是 提供一些增强能力,这种场景可以说是微应用粒度的前端组件化。
即: qiankun 相当于 route-based 的控制台应用,做为一个微应用的聚合框架而被使用。
使用步骤:
1. 主应用安装
yarn add qiankun # or npm i qiankun -S
2. 在主应用中注册微应用
import { registerMicroApps,runAfterFirstMounted, start } from 'qiankun'
// window.qiankunStarted 为严谨,防止加载多次 (可省略)
if (!window.qiankunStarted) {
window.qiankunStarted = true
registerMicroApps(
[
{
name: 'invoice', // 子应用名的标识
entry: `${process.env.VUE_APP_INVOICE_URL}`, // 子应用的目标地址, 可在环境变量中配置
container: '#subapp-viewport', // 把加载到的子路由界面放在某个容器中
// loader,
activeRule: '/invoice', // 加载以/invoice开头的路由
},
],
// 主应用的生命周期
// {
// beforeLoad: [
// app =>{
// console.log('[LifeCycle] before load %c%s', 'color: green', app.name)
// },
// ],
// beforeMount: [
// app =>{
// console.log('[LifeCycle] before mount %c%s', 'color: green', app.name)
// },
// ],
// afterUnmount: [
// app =>{
// console.log('[LifeCycle] after unmount %c%s', 'color: green', app.name)
// },
// ],
// },
)
// 初始化主应用属性
// const { onGlobalStateChange, setGlobalState } = initGlobalState({
// // user: 'qiankun',
// })
// onGlobalStateChange((value, prev) =>console.log('[onGlobalStateChange - master]:', value, prev))
// 设置自定义属性可传参到子应用中, 在子应用的mounted钩子中使用prop属性来接受
// setGlobalState({
// // ignore: 'master',
// // user: {
// // name: 'master',
// // },
// })
// setDefaultMountApp('/')
start()
// runAfterFirstMounted(() =>{
// console.log('[MainApp] first app mounted')
// })
}
当微应用信息注册完之后,一旦浏览器的 url 发生变化,便会自动触发 qiankun 的匹配逻辑,所有 activeRule 规则匹配上的微应用就会被插入到指定的 container 中,同时依次调用微应用暴露出的生命周期钩子。
3. 配置渲染微应用容器的路由
3. 在微应用中导出相应的生命周期钩子
3.1. 在微应用的 src 目录新增 public-path.js
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
3.2. 修改微应用中的路由文件router.js ,根据微应用标识限制路由范围
3.3. 入口文件 main.js 修改,为了避免根 id #app 与其他的 DOM 冲突,需要限制查找范围。
// 在微应用中的main.js中配置
let instance = null
function render(props = {}) {
// props对象中的container属性指的是主应用的dom
const { container } = props
instance = new Vue({
router,
store,
render: (h) =>h(App),
}).$mount(container ? container.querySelector('#app') : document.querySelector('#app'))
}
// 独立运行微应用时
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
/**
* bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
*/
export async function bootstrap() {
console.log('[vue] vue app bootstraped')
}
// 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
export async function mount(props) {
console.log('[vue] props from main framework', props)
render(props)
}
// unmount时销毁应用, 防止内存泄漏
export async function unmount() {
instance.$destroy()
instance.$el.innerHTML = ''
instance = null
}
4. 配置微应用的打包工具(vue.config.js)
const { name } = require('./package')
module.exports = {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
},
configureWebpack: {
output: {
library: `invoice`, // 应用标识, 和name保持一致
libraryTarget: 'window', // 把微应用打包成window格式
jsonpFunction: `webpackJsonp_${name}`,
},
},
}
使用qiankun微应用需要注意几点:
1. 在微应用src中新增 public-path.js 文件,用于修改运行时的 publicPath
2. 微应用建议使用 history 模式的路由,需要设置路由 base,值和它的 activeRule 是一样的。
3. 在入口文件最顶部引入 public-path.js,修改并导出三个生命周期函数。
4. 修改 webpack 打包。
主应用路由配置需要注意到的点:
1. 微应用入口路由需配置在主应用的后面. 否则主应用的界面显示不出来
2. 如遇到路由显示的顺序问题, 如上图, 第一个路由菜单需显示在左侧导航栏的最后面, 可以给每个路由设置order属性, 用于在渲染导航栏菜单之前进行排序.
3. 如遇到样式冲突, 则各自加载各自的vue和elementUI