使用 UMI + Qiankun 搭建主基座应用和微应用
框架地址
React 框架:UMI 文档地址
Qiankun 框架: Qiankun地址
废话不多说了,直接看代码
创建主基座应用
Step1: 使用 umi 的脚手架创建项目
# 创建主项目
yarn create @umijs/umi-app
# 添加 `qiankun-plugin`
yarn add @umijs/plugin-qiankun -D
下面是一份比较完整的 package.json
{
"private": true,
"scripts": {
"start": "umi dev",
"build": "umi build",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"test:coverage": "umi-test --coverage"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,less,md,json}": [
"prettier --write"
],
"*.ts?(x)": [
"prettier --parser=typescript --write"
]
},
"dependencies": {
"react": "17.x",
"react-dom": "17.x",
"umi": "3.5.19",
"@umijs/plugin-qiankun": "2.33.1"
},
"devDependencies": {
"@types/react": "17.0.0",
"@types/react-dom": "17.0.0",
"@umijs/preset-react": "1.x",
"@umijs/test": "3.5.19",
"lint-staged": "10.0.7",
"prettier": "2.2.0",
"typescript": "4.1.2",
"yorkie": "2.0.0"
}
}
Step2: 配置.umirc.ts 文件
# .umirc.ts
# 在开发模式下,主应用加载微应用的图片等静态资源的代理
proxy: {
'/xx': {
target: 'http://localhost:xxxx',
changeOrigin: true,
},
},
# 开启`qiankun`主应用
qiankun: {
master: {},
},
Step3: 创建 app.ts,定义qiankun相关微应用和路由,以及全局变量等数据
此处只定义了 lang 和 userInfo 两个变量,lang 代表语言,userInfo 代表用户信息
# src/app.ts
import { useState } from 'react';
import actions from '@/qiankun/action';
export function useQiankunStateForSlave() {
const [qiankunMainState, setQiankunMainState] = useState<QiankunStateProps>({
lang: 'zh-CN',
userInfo: null,
});
// 实际给子应用调用修改state的方法
// 传参和实现可以自定义,子应用直接调用setGlobalState是不生效的,所以才需要这个额外的方法,这是一个坑
const microSetQiankunState = (state: QiankunStateProps) => {
const allStates = Object.assign(qiankunMainState, state);
setQiankunMainState(allStates);
actions.setGlobalState(allStates);
};
return {
qiankunMainState,
microSetQiankunState,
};
}
export const qiankun = () => {
return {
apps: [
{
name: 'user',
entry: '//localhost:xxxx',
}
],
routes: [
{
path: '/user',
microApp: 'user',
microAppProps: {
autoSetLoading: true,
className: 'userContainer',
wrapperClassName: 'userWrapper',
},
}
],
lifeCycles: {
beforeLoad: (app: any) => {
console.log('app before load', app);
},
afterMount: (app: any) => {
console.log('app after mount', app);
},
},
sandbox: {
experimentalStyleIsolation: true,
},
prefetch: true,
};
};
Step4: 在主应用中修改全局变量的值。
在上面的
app.ts中,我们定义了microSetQiankunState,可以使用这个方法改变数据值
# src/models/useAuthModel.ts
...
const currentUser = { realname: 'xxx', username: 'xxx', sex: 'xxx', ... }
microSetQiankunState({ userInfo: currentUser })
...
Step5: 创建action, 监听全局变量的变化,比如主应用数据更改或者从微应用传递上来的数据
# src/qiankun/action.tsx
import { initGlobalState, MicroAppStateActions } from 'qiankun';
export const initialState: QiankunStateProps = {
lang: "zh-CN",
userInfo: null
};
const actions: MicroAppStateActions = initGlobalState(initialState);
// 使用下面的方法,可以在主应用的任意界面,监听数据的状态变化
// actions.onGlobalStateChange((state: QiankunStateProps, prev: QiankunStateProps) => {
// console.log('主应用状态变更 :: ', state, prev);
// }, true);
export default actions;
Step6: 监听从微应用传递过来的lang,从而改变主基座应用和微应用的语言
# src/layout/index.tsx
import { useEffect } from 'react'
import actions from '@/qiankun/action'
const BasicLayout = ({ children }: any) => {
useEffect(() => {
actions.onGlobalStateChange((state: QiankunStateProps, prev: QiankunStateProps) => {
console.log('主应用状态变更 :: ', state, prev);
// 修改语言
// changeLang(state.lang || 'zh-CN', false)
}, true);
}, [])
return <><div>Baisc Layout</div><div>{children}</div></>
}
export default BasicLayout
创建微应用
Step1: 使用umi脚手架创建应用
# 创建主项目
yarn create @umijs/umi-app
# 添加 `qiankun-plugin`
yarn add @umijs/plugin-qiankun -D
下面是一份比较完整的 package.json,仅供参考
{
"name": "yuestone-wms-app",
"private": true,
"version": "1.0.0",
"scripts": {
"start": "umi dev",
"build": "umi build",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"test:coverage": "umi-test --coverage"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,less,md,json}": [
"prettier --write"
],
"*.ts?(x)": [
"prettier --parser=typescript --write"
]
},
"dependencies": {
"@umijs/plugin-qiankun": "2.33.1",
"react": "17.x",
"react-dom": "17.x",
"umi": "3.5.19"
},
"devDependencies": {
"@types/react": "17.0.0",
"@types/react-dom": "17.0.0",
"@umijs/preset-react": "1.x",
"@umijs/test": "3.5.19",
"lint-staged": "10.0.7",
"prettier": "2.2.0",
"typescript": "4.1.2",
"yorkie": "2.0.0"
}
}
Step2: 配置.umirc.ts文件
# 配置`qiankun`的`slave`
qiankun: {
slave: {}
}
Step3: 创建public-path.js
/* eslint-disable no-undef */
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
Step4: 创建global.d.ts文件
interface Window {
__POWERED_BY_QIANKUN__: string;
}
Step5: 创建 action.tsx
# src/qiankun/action.tsx
import { initGlobalState, OnGlobalStateChangeCallback, MicroAppStateActions } from 'qiankun';
class Actions {
// 默认值为空 Action
actions: MicroAppStateActions = initGlobalState({});
/**
* 设置 actions
*/
setActions(actions: any) {
this.actions = actions;
}
/**
* 映射
*/
onGlobalStateChange(cb: OnGlobalStateChangeCallback, fireImmediately?: boolean) {
return this.actions.onGlobalStateChange(cb, fireImmediately);
}
/**
* 映射
*/
setGlobalState(state: Record<string, any>) {
return this.actions.setGlobalState(state);
}
}
const actions = new Actions();
export default actions;
Step6: 创建app.tsx,定义qiankun相关界面内容以及相关生命周期
import ReactDOM from "react-dom";
import { BrowserRouter } from 'react-router-dom';
import App from './pages/index'
import './public-path';
import actions from "@/qiankun/action";
function render(props: any) {
const { base, container } = props;
ReactDOM.render(
<BrowserRouter basename={window.__POWERED_BY_QIANKUN__ ? base : '/'}>
<App />
</BrowserRouter>,
container ? container.querySelector('#root') : document.querySelector('#root'),
);
}
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
export const qiankun = {
// 应用加载之前
async bootstrap(props: any) {
console.log('子应用[WMS] bootstrap', props)
},
// 应用 render 之前触发
async mount(props: any) {
console.log('子应用[WMS] mount', props)
actions.setActions(props)
render(props);
},
// 应用卸载之后触发
async unmount(props: any) {
console.log('子应用[WMS] unmount', props)
const { container } = props;
ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') : document.querySelector('#root'));
},
}
Step7: 使用从微应用传递过来的值
比如可以在
layout界面设置微应用的语言
# src/layout/index.tsx
import { useEffect } from 'react'
import actions from '@/qiankun/action'
const BasicLayout = ({ children }: any) => {
useEffect(() => {
actions.onGlobalStateChange((state: QiankunStateProps, prev: QiankunStateProps) => {
if (prev.lang !== state.lang) {
// 更新语言
changeLang(state.lang || 'zh-CN');
}
}, true);
})
return <><div>Basic Layout</div><div>{children}</div><>
}
export default BasicLayout
感谢
到此,本篇文章先告一段落,如果有什么错误或不足,欢迎评论区指正!感谢您的阅读~~