简介
qiankun
是一个基于 single-spa 的微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。
什么是微前端(官网抄的)
微前端架构具备以下几个核心价值:
技术栈无关 主框架不限制接入应用的技术栈,微应用具备完全自主权
独立开发、独立部署 微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
增量升级
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
独立运行时 每个微应用之间状态隔离,运行时状态不共享
微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用( Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。
qiankun接入核心
- 基座应用与子应用都需要安装
qiankun
依赖 - 基座应用注册子应用
- 子应用修改打包输出为umd、同时解决dev环境跨域问题(cors方案,可参考qiankun官方文档)
javascript
const { name } = require('./package');
module.exports = {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`, // webpack 5 需要把 jsonpFunction 替换成 chunkLoadingGlobal
},
},
};
- 子应用暴露
qiankun
生命周期钩子
接入场景与接入流程
接入场景主要分为umi
项目和非umi
项目,原因是因为umi
提供了@umijs/plugin-qiankun
插件一键开启微前端。
场景一
- 基座应用与子应用都非
umi
项目
接入流程
- 主子应用安装
qiankun
依赖 - 主应用在项目入口文件中注入子应用
js
import {registerMicroApps, start} from 'qiankun';
registerMicroApps([{
name: 'child', // app name registered
entry: '//localhost:8080', //子应用项目入口地址
container: '#container', //微前端挂在节点
activeRule: '/', //匹配路由
props: { //初始化通信数据
eventName: "TransferValue",
}
}]);
start(); //开启qiankun
- 子应用入口文件暴露
qiankun
生命周期钩子函数
js
export async function bootstrap() {
console.log(' react app bootstraped');
}
export async function mount(props) {
}
export async function unmount(props) {
}
- 子应用需要在
mount
和unmount
去找到应用的挂在点和应用的卸载点
js
function render(props) {
const {container} = props;
ReactDOM.render(<App/>, container ? container.querySelector('#root') : document.querySelector('#root'));
}
if (!window.__POWERED_BY_QIANKUN__) {
render({});
} //判断应用是否为qiankun挂在
export async function mount(props) {
console.log(props)
render(props);
}
export async function unmount(props) {
const {container} = props;
ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') : document.querySelector('#root'));
}
- 修改
webpack
(vite
同理)打包配置,以下以create-react-app
脚手架项目为例;安装react-app-rewired
依赖,然后在项目目录下新建config-overrides.js文件
,配置打包,修改启动脚本。
6. 完成接入
场景二
- 基座应用非umi项目
- 子应用umi4
接入流程
- 基座应用接入流程不变
- 子应用
umi4
分为umi-max
和umi-simple-app
以umi-simple-app
子应用接入为例 umi-simple-app
安装umi
插件集@umijs/plugins
- 在umi配置文件中开启
qiankkun
插件并且开启子应用qiankun
配置
js
export default defineConfig({
plugins: ["@umijs/plugins/dist/qiankun"],
qiankun:{
slave:{}
},
});
- 在
app.js
文件中开启qiankun
生命周期
js
export const qiankun = {
// 应用加载之前
async bootstrap(props: any) {
console.log('app2 bootstrap', props);
},
// 应用 render 之前触发
async mount(props: any) {
console.log('app2 mount', props);
},
// 应用卸载之后触发
async unmount(props: any) {
console.log('app2 unmount', props);
},
};
- 接入完成(
umi-max
内部集成qiankun
插件、直接启动qiankun
配置、暴漏出qiankun
生命周期钩子即可)
场景三
- 基座应用与子应用都是umi4
接入流程
- 基座应用和子应用同时安装
@umijs/plugins
,在umi配置文件中开启qiankun
插件配置
js
plugins: ["@umijs/plugins/dist/qiankun"]
umi-max
跳过此步骤、umi-max
集成了此插件
- 基座应用开启
qiankun
配置
js
qiankun: {
master: {
apps: [
{
name: "child1",
entry: "//localhost:3010"
},
]
}
}
- 基座应用注入路由使用
microApp
匹配子应用
js
routes: [{path: "/child1", microApp: "child1"}]
基座应用配置完毕
- 子应用开启
qiankun
配置、并注入路由
js
export default defineConfig({
plugins: ["@umijs/plugins/dist/qiankun"],
qiankun:{
slave:{}
},
base:"/child2",
routes: [
{ path: "/", component: "index" },
],
npmClient: 'pnpm',
});
- 在app.js入口文件中暴漏
qiankun
生命周期
js
export const qiankun = {
// 应用加载之前
async bootstrap(props: any) {
console.log('app2 bootstrap', props);
},
// 应用 render 之前触发
async mount(props: any) {
console.log('app2 mount', props);
},
// 应用卸载之后触发
async unmount(props: any) {
console.log('app2 unmount', props);
},
};
- 接入流程完毕
小结
qiankun
的使用场景主要分为umi
项目或者非umi
项目umi
项目无论基座应用还是子应用都可以使用umi
自动封装的插件快速开启微前端配置- 非
umi
无论基座应用还是子应用都可以根据qiankun
官方文档开启微前端配置 - 基座应用和子应用可根据上面场景灵活搭配
通信
umi
项目(无论是基座还是子应用)核心都是通过useModel
,参考:umijs.org/docs/max/da...
基座应用在app.js中暴漏出的useQiankunStateForSlave
函数
js
export function useQiankunStateForSlave() {
const [globalState, setGlobalState] = useState<any>({
slogan: 'Hello MicroFrontend',
});
return {
globalState,
setGlobalState,
};
}
子应用在需要使用的地方直接通过以下使用
js
const masterProps = useModel('@@qiankunStateFromMaster');
子应用打包成静态资源引入场景场景
在qiankun
的文档中entry支持配置成对象,html一定是html字符串,script可以配置为需要注入的脚本地址 如以下所示:
js
fetch('http://localhost:7001/dist/index.html') // 配置静态资源地址
.then(response => response.text())
.then(htmlString => {
console.log(htmlString)
registerMicroApps([{
name: 'qiankun', // app name registered
entry: {
html: htmlString,
scripts: ["http://localhost:7001/dist/umi.js", "http://localhost:7001/dist/p__index.async.js"] //需要注入的脚本地址
},
container: '#root-subapp-container', activeRule: '/test',
}]);
start();
})
.catch(error => {
console.error('Error fetching the HTML file:', error);
});
注意
- 基座应用与子应用路由的模式需要同一,比如基座应用是hash路由,子应用也需要配置hash路由
- 路由路径要同一(因为子应用需要基座应用注入的路由去进行匹配)