一、qiankun 是什么?
qiankun 是一个基于 single-spa 的微前端实现库,是一个微前端架构系统。
二、核心价值
- 技术栈无关
- 独立开发、独立部署
- 增量升级
- 独立运行时:状态隔离,运行时状态不共享
三、宗旨和核心目标
旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。
四、为什么不是用iframe
iframe最大的问题就是提供了浏览器原生的隔离方案,不论是样式隔离,js隔离这类问题统统都能被完美解决。
但最大的问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享。
五、特性
📦 基于 single-spa 封装,提供了更加开箱即用的 API。
📱 技术栈无关,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架。
💪 HTML Entry 接入方式,让你接入微应用像使用 iframe 一样简单。
🛡 样式隔离,确保微应用之间样式互相不干扰。
🧳 JS 沙箱,确保微应用之间 全局变量/事件 不冲突。
⚡️ 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
🔌 umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统。
六、基本使用(以vue为例)
1)新建主应用
新建主应用:
vue create qiankun-base
安装 qiankun
:
yarn add qiankun # 或者 npm i qiankun -S
main.js 注册微应用并启动:
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'micro-vue-app1',
entry: '//localhost:3000',
container: '#container1',
activeRule: '/micro-vue-app1',
},
{
name: 'micro-vue-app2',
entry: '//localhost:8080',
container: '#container2',
activeRule: /micro-vue-app2',
},
]);
// 启动 qiankun
start();
在界面上写入挂载微应用的id
修改app.vue的组件代码:
<template>
<div id="app">
<div>
<router-link to="/micro-vue-app1>微应用1</router-view>
<router-link to="/micro-vue-app2">微应用2</router-view>
</div>
<router-view></router-view>
<div id="container1"></div>
<div id="container2"></div>
</div>
</template>
2)新建微应用1
1、在src目录新增 public-path.js 文件,用于修改运行时的 publicPath。
如果没有加这个,会导致微应用的静态资源访问不了。
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
2、在入口文件main.js最顶部引入 public-path.js,修改并导出三个生命周期函数(bootstrap
,mount
,unmount
)。
import './public-path';
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import routes from './router';
import store from './store';
Vue.config.productionTip = false;
let router = null;
let instance = null;
function render(props = {}) {
const { container } = props;
router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? '/app-vue/' : '/',
mode: 'history',
routes,
});
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
console.log('[vue] props from main framework', props);
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
}
3、修改 webpack 打包,允许开发环境跨域和 umd 打包。
const { name } = require('./package');
module.exports = {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`,
},
},
};
3)新建微应用2
和微应用1一样的步骤
4)主应用和微应用之间如何通信
主应用初始化state,监听state的变化
import { initGlobalState, MicroAppStateActions } from 'qiankun';
let state = {
name: '你的益达'
}
// 初始化 state
const actions: MicroAppStateActions = initGlobalState(state);
actions.onGlobalStateChange((state, prev) => {
// state: 变更后的状态; prev 变更前的状态
console.log(state, prev);
});
actions.setGlobalState(state);
actions.offGlobalStateChange();
在子应用的mount里面接收到props,并监听state的变化,还可以设置state的值
export async function mount(props) {
console.log('[vue] props from main framework', props);
props.onGlobalStateChange((state, prev) => {
// state: 变更后的状态; prev 变更前的状态
console.log(state, prev);
});
props.setGlobalState(state);
}
参考:qiankun