Micro front-end series - application integration (qiankun + umi + vue)

Micro front-end project selection

Main application: umi + Ant Design Sub-application: vue + element

Routing mode: main application (history), sub-application (hash)

Basic configuration

1. Main application qiankun configuration

(1) Install dependency packages

yarn add -D @umijs/plugin-qiankun
复制代码

(2) Registering sub-applications

There are two ways to register sub-applications, 二选一即可:

a. Configure sub-applications during plugin build time
// config.js

export default: {
    qiankun: {
        master: {
            // 注册子应用信息
            apps: [
                {
                    name: 'app1',
                    entry: '//localhost:7001'
                },
                {
                    name: 'app2',
                    entry: '//localhost:7002'
                }
            ]
        }
    }
}
复制代码
b. Dynamically configure sub-applications at runtime (open in 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) Loading sub-applications

There are two ways to load sub-applications, 二选一即可:

a. Using route binding

It is recommended to use this method to import sub-applications with their own routes

// config/router.config.ts
export default {
  routes: [
    // 配置子应用 reactApp 关联的路由
    {
      name: 'react子应用',
      path: '/subreact',
      microApp: 'reactApp',
    },
    // 配置子应用 vueApp 关联的路由
    {
      name: 'vue子应用',
      path: '/subvue',
      microApp: 'vueApp',
    },
  ],
};
复制代码
b. How to use <MicroApp />components

It is recommended to use this method to import sub-applications without routing.

import { MicroApp } from 'umi'

export function MyPage() {
    return (
        <div>
            <MicroApp name="app1" />
        </div>
    )
}
复制代码

2. Sub-application qiankun configuration

(1) Entry file main.js

bootstrapThe sub-application needs to export three declaration cycle hooks mountin its own entry file unmountfor the main application to call at the appropriate time.

bootstrap: It will only be called once when the sub-app is initialized. The mount hook will be called directly when the sub-app re-enters next time, and bootstrap will not be triggered repeatedly. Usually we can do some initialization of global variables here, such as application-level caches that will not be destroyed in the unmount phase.

mount: The mount method is called every time the application enters, usually we trigger the rendering method of the application here.

unmount: 切除/卸载The method that the application will call each time, usually here we will unmount the application instance of the sub-application.

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) In the project root directory, add a new filepublic-path.js

if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
复制代码

(3) The configuration file vue.config.js is added

In addition to exposing the corresponding lifecycle hooks in the code, in order for the main application to correctly identify the information exposed by the sub-application, the packaging tool of the sub-application needs to add the following configuration

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. The main and sub-applications implement communication configuration

(1) The main application umi project communicates with the vue sub-application

  • New src => action.ts file
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>
复制代码

子应用改造

登录逻辑改造

打通登录权限,主应用登录后,切换子应用不需要再次进行登录检验,实现免登录功能

未命名白板 (1).png

Guess you like

Origin juejin.im/post/7078272210019811359