微前端项目选型
主应用:umi + Ant Design 子应用:vue + element
路由模式:主应用(history),子应用 (hash)
基础配置
1. 主应用 qiankun 配置
(1) 安装依赖包
yarn add -D @umijs/plugin-qiankun
复制代码
(2) 注册子应用
子应用注册有两种方式,二选一即可
:
a.插件构建期配置子应用
// config.js
export default: {
qiankun: {
master: {
// 注册子应用信息
apps: [
{
name: 'app1',
entry: '//localhost:7001'
},
{
name: 'app2',
entry: '//localhost:7002'
}
]
}
}
}
复制代码
b.运行时动态配置子应用(src/app.ts里开启)
// 从接口中获取子应用配置,export 出的 qiankun 变量时一个 promise
export const qiankun = fetch('/config').then(({ apps }) => ({
// 注册子应用信息
apps,
lifeCycles: {
afterMount: (props) => {
console.log(props);
},
},
// 支持更多的其他配置,详细请看这里:https://qiankun.umijs.org/zh/api/#start-opts
}));
复制代码
(3) 装载子应用
子应用的装载有两种方式,二选一即可
:
a.使用路由绑定的方式
建议使用这种方式来引入自带路由的子应用
// config/router.config.ts
export default {
routes: [
// 配置子应用 reactApp 关联的路由
{
name: 'react子应用',
path: '/subreact',
microApp: 'reactApp',
},
// 配置子应用 vueApp 关联的路由
{
name: 'vue子应用',
path: '/subvue',
microApp: 'vueApp',
},
],
};
复制代码
b.使用 <MicroApp />
组件的方式
建议使用这种方式来引入不带路由的子应用。
import { MicroApp } from 'umi'
export function MyPage() {
return (
<div>
<MicroApp name="app1" />
</div>
)
}
复制代码
2. 子应用 qiankun 配置
(1) 入口文件 main.js
子应用需要在自己的入口文件导出 bootstrap
, mount
, unmount
三个声明周期钩子,以供主应用在适当的时机调用。
bootstrap: 只会在子应用初始化的时候调用一次,下次子应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
mount:应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法。
unmount:应用每次切除/卸载
会调用的方法,通常在这里我们会卸载子应用的应用实例。
let instance = null;
function render() {
instance = new Vue({
router, store, render: h => h(App)
}).$mount('#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;
}
复制代码
(2) 在项目根目录下,新增文件 public-path.js
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
复制代码
(3) 配置文件 vue.config.js 新增
除了代码中暴露出相应的生命周期钩子之外,为了让主应用能正确识别子应用暴露出来的信息,子应用的打包工具需要增加如下配置
const port = 9528;
module.exports = {
publicPath: process.env.ENV === 'development' ? `//localhost:${port}` : './',
devServer: {
port: port,
headers: {
// 允许跨域
'Access-Control-Allow-Origin': '*'
}
},
configureWebpack: {
output: {
// 输出暴露的名称
library: `${name}-[name]`,
libraryTarget: 'umd', // 将微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`
}
}
}
复制代码
3. 主子应用实现通信配置
(1) 主应用 umi 项目 向 vue 子应用通信
- 新建 src => action.ts 文件
import { initGlobalState } from 'qiankun';
const initialState = {
// 初始化数据
projectId: ''
};
// 初始化 state
const actions = initGlobalState(initialState);
export default actions;
复制代码
- 在组件中使用 actions
import actions from '@/actions';
export function ProComp() {
const onChangePro = () => {
actions.setGlobalState({ projectId: '123' })
};
return <button onClick={onChangePro} >更改项目信息</button>
}
复制代码
(2) 子应用 vue 项目
使用 qiankun 官方提供的通信方式 - Actions 通信去实现
- 新建 src => actions.js 文件
function emptyAction() {
// 设置一个 actions 实例
// 提示当前使用的是空 Action
console.log('Current execute action is empty!')
}
class Actions {
// 默认值为空 Action
actions = {
onGlobalStateChange: emptyAction,
setGlobalState: emptyAction
}
// 设置 actions
setActions(actions) {
this.actions = actions;
}
// 映射,注册观察者函数,响应 globalState 变化
onGlobalStateChange(...args) {
return this.actions.onGlobalStateChange(...args)
}
// 映射,设置 globalState
setGlobalState(...args) {
return this.actions.setGlobalState(...args)
}
}
const actions = new Actions();
export default actions;
复制代码
- 入口文件 main.js
在 mount 生命周期里注入 actions 实例
import actions from './actions';
export async function mount(props) {
actions.setActions(props); // 注入 actions 实例
render(props)
}
复制代码
- 使用范例
<template>
<div>
<div>这是子应用</div>
<p>接收到的消息: {{mes}}</p>
<button @click= "btnClick">点击向父应用发送消息</button>
</div>
</template>
<script>
import actions from '../actions'; // 导入实例
export default {
data() {
return {
mes: '',
}
},
mounted() {
actions.onGlobalStateChange((state) => { // 监听全局状态
this.mes = state
}, true);
},
methods:{
btnClick(){
actions.setGlobalState({ info: '123'}) // 改变全局状态
}
}
}
</script>
复制代码
子应用改造
登录逻辑改造
打通登录权限,主应用登录后,切换子应用不需要再次进行登录检验,实现免登录功能