主应用
1. 安装 qiankun
$ yarn add qiankun # 或者 npm i qiankun -S
qiankun只需要主应用安装呦,微应用(子应用)只需要导出指定的生命周期钩子
2. 在主应用中注册微应用
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
// name - string - 必选,微应用的名称,微应用之间必须确保唯一。
name: 'react app',
/**
* entry
* `string | { scripts?: string[]; styles?: string[]; html?: string }`
* 必选,微应用的入口
* 配置为字符串时,表示微应用的访问地址,例如 `https://qiankun.umijs.org/guide/`
* 配置为对象时,`html` 的值是微应用的 html 内容字符串,而不是微应用的访问地址。微应用的 `publicPath` 将会被设置为 `/`
*/
entry: '//localhost:7100',
/**
* container
* `string | HTMLElement`
* 必选,微应用的容器节点的选择器或者 Element 实例。
* 如`container: '#root'` 或 `container: document.querySelector('#root')`。
*/
container: '#yourContainer',
/**
* activeRule
* `string | (location: Location) => boolean
* Array<string | (location: Location) => boolean> `
* 必选,微应用的激活规则
*/
activeRule: '/yourActiveRule',
},
{
name: 'vue app',
entry: { scripts: ['//localhost:7100/main.js'] },
container: '#yourContainer2',
activeRule: '/yourActiveRule2',
},
]);
// 启动 qiankun
start();
当微应用信息注册完之后,一旦浏览器的 url 发生变化,便会自动触发 qiankun 的匹配逻辑,所有 activeRule 规则匹配上的微应用就会被插入到指定的 container 中,同时依次调用微应用暴露出的生命周期钩子。
注意container要在主应用预留好坑位,便于微服务(子应用)插入 例如主应用使用vue框架在app.js文件中
<template>
<div>
// 主应用模块
<el-menu :router="true" mode="horizontal">
<!-- 主应用中也可以放自己的路由 -->
<el-menu-item index="/">首页</el-menu-item>
<!-- 引用其他的子应用 -->
<el-menu-item index="/vue">vue应用</el-menu-item>
<el-menu-item index="/react">react应用</el-menu-item>
</el-menu>
<router-view v-show="$route.name"></router-view>
// 子应用预留坑位
<div id="vue"></div>
<div id="react"></div>
</div>
</template>
如果微应用不是直接跟路由关联的时候,你也可以选择手动加载微应用的方式:
import { loadMicroApp } from 'qiankun';
loadMicroApp({
name: 'app',
entry: '//localhost:7100',
container: '#yourContainer',
});
微应用(子应用)
微应用不需要额外安装任何其他依赖即可接入 qiankun 主应用。
1. 导出相应的生命周期钩子
微应用需要在自己的入口 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);
}
举个🌰react示例:
// index.js文件
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
function render(){
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
}
if(!window.__POWERED_BY_QIANKUN__){
render();
}
export async function bootstrap(){
}
export async function mount() {
render()
}
export async function unmount(){
ReactDOM.unmountComponentAtNode( document.getElementById('root'));
}
举个🌰vue示例
// main.js文件
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
let instance = null;
function render(props) {
// props 组件通信
instance = new Vue({
router,
render: h => h(App)
}).$mount('#app') // 这里是挂载到自己的HTML中,基座会拿到这个挂载后的HTML,将其插入进去
}
if (!window.__POWERED_BY_QIANKUN__) { // 如果是独立运行,则手动调用渲染
render();
}
if(window.__POWERED_BY_QIANKUN__){ // 如果是qiankun使用到了,则会动态注入路径
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// 根据 qiankun 的协议需要导出 bootstrap/mount/unmount
export async function bootstrap(props) {
};
export async function mount(props) {
render(props);
};
export async function unmount(props) {
instance.$destroy();
};
qiankun 基于 single-spa,所以你可以在这里找到更多关于微应用生命周期相关的文档说明。
无 webpack 等构建工具的应用接入方式请见这里
2. 配置微应用的打包工具
除了代码中暴露出相应的生命周期钩子之外,为了让主应用能正确识别微应用暴露出来的一些信息,微应用的打包工具需要增加如下配置:
webpack:
const packageName = require('./package.json').name;
module.exports = {
output: {
library: `${packageName}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${packageName}`,
},
devServer: {
headers:{
'Access-Control-Allow-Origin': '*' // 允许跨域
}
},
};
相关配置介绍可以查看 webpack 相关文档。