Implementation of communication between qiankun micro front end applications

Posted by jf3000 on Sat, 11 Dec 2021 12:37:39 +0100

signal communication



Before introducing the application communication of "qiankun", we need to understand how the micro front-end architecture divides sub applications.

In the micro front-end architecture, we should divide the corresponding sub applications by business, rather than dividing the sub applications by functional modules. There are two reasons for this:

  1. In the micro front-end architecture, the sub application is not a module, but an independent application. We can have better maintainability and decoupling by dividing the sub application by business.
  2. Sub applications should have the ability to run independently. Frequent communication between applications will increase the complexity and coupling of applications.

To sum up, we should divide each sub application from the perspective of business to reduce the communication between applications as much as possible, so as to simplify the whole application and make our micro front-end architecture more flexible and controllable.

We will introduce two communication methods in this tutorial,

  1. The first is action communication, an official communication method provided by qiankun. It is suitable for micro front-end applications with clear business division and relatively simple. Generally speaking, the first scheme can meet the needs of most application scenarios.
  2. The second is Storage communication, which is based on local Storage and sessionStorage. It is suitable for tracking the communication status, such as login information and token. The sub application has the ability to run independently.
  3. The third method is based on props, which is used to transfer values from the main application to the sub application. It is applicable to shared components of main and sub applications, public method calls, etc.



Actions communication

Let's first introduce the official inter application communication mode - Actions communication. This communication mode is more suitable for micro front-end application scenarios with clear business division and less inter application communication.



Communication principle

The "initGlobalState" method provided by qiankun is used to register the "MicroAppStateActions" instance for communication. The instance has three methods, namely:

  • setGlobalState: set global state - when setting a new value, a shallow check will be performed internally. If it is detected that the global state has changed, a notification will be triggered to notify all observers of the global state function.
  • onGlobalStateChange: register the {observer} function - respond to the change of} global state and trigger the} observer function when the} global state changes.
  • offGlobalStateChange: cancels the "Observer" function - the instance no longer responds to "globalState" changes.

Let's draw a picture to help you understand (see the figure below)

 

As can be seen from the above figure, we can register "Observer" into the observer pool first, and then modify "globalState" to trigger all "Observer" functions, so as to achieve the effect of communication between components.

Api

API description - qiankun

Understanding: the global state here is very similar to the state in vuex, except that the global state can be shared in the main application and micro application



Simple experiment



Main application

New SRC - > actions js

import { initGlobalState } from 'qiankun';

import store from './store';

const initialState = {
    //Write initialization data here
};

// Initialize state
const actions = initGlobalState(initialState);
actions.onGlobalStateChange((state, prev) => {
    //Monitor changes in public status
    console.log('Main application: Before change');
    console.log(prev);
    console.log('Main application: After change');
    console.log(state);
    store.commit('setProject', state); //Here I save the public state in the vuex of the main application
});

export default actions;

Using actions in components

tab.vue

<template>
  <div>
    <button @click="sendMes1">
      Click send message 1 to sub application</button>
    <button @click="sendMes2">
      Click send message to subapplication 2</button>
    <p>
      Currently displayed items:{{project}}
    </p>
  </div>
  </template>
  <script>

    import actions from './actions'//Remember to import the actions instance
    export default {
      data() {
        return

        {
          mes1: { project_id: 'Item 1' },
          mes2: { project_id: 'Item 2' },
        }

      },
      computed: {
        project: function () {
          return this.$store.state.project_id
        }

      },
      methods: {
        sendMes1() {
          actions.setGlobalState(this.mes1);//Changing the global state through setGlobalState
        },

        sendMes2() {
          actions.setGlobalState(this.mes2);
        }
      },
    }
  </script>



Micro application

New SRC - > actions js

function emptyAction() {
    //Set an actions instance
    // Prompt: empty Action is currently used
    console.warn('Current execute action is empty!');
}

class Actions {
    // The default value is empty Action
    actions = {
        onGlobalStateChange: emptyAction,
        setGlobalState: emptyAction,
    };

    /**
     * Set actions
     */
    setActions(actions) {
        this.actions = actions;
    }

    /**
     * mapping
     */
    onGlobalStateChange(...args) {
        return;

        this.actions.onGlobalStateChange(...args);
    }

    /**
     * mapping
     */
    setGlobalState(...args) {
        return;

        this.actions.setGlobalState(...args);
    }
}

const actions = new Actions();
export default actions;

main.js

Inject the actions instance into the mounted lifecycle

export async function mount(props) {
    actions.setActions(props);
    //Inject actions instance
    render(props);
}

Use in vue components

1.vue

<template>
  <div>
    <div>
      This is a sub application
    </div>
    <p>Received message:{{mes}}</p>
    <button @click="butClick">Click send message to parent app</button>
  </div>
</template>
<script>
  import actions from '../actions'//Import instance
  export default {
    data() {
      return { mes: '', }
    },
    mounted() {
      actions.onGlobalStateChange((state) => {
        //Listen for global status
        this.mes = state
      }, true);
    },
    methods: {
      butClick() {
        actions
          .setGlobalState({
            project_id: 'Item 99'
          })//Change global state
      }

    }
  }
</script>

Storage communication

Communication principle

storage Namespace,See for detailsportal/src/utils/storageNameSpace.js
  • Stored value in main application sesstionstorage setItem('a', 'b', true)
/ / the "main application: a" will be automatically added to the key as the key
Value sesstionstorage getItem('a', true)
Clear the value sessionstorage removeItem('a', true)
Empty 
      sessionStorage.clear(true) / / clear all sessionstorage, including sub applications
      sessionStorage.clear('self ') / / clear the sessionstorage of the main application
  • Sub application
Stored value sessionstorage setItem('a', 'b')  
    // 'Application Name: a' will be automatically added to the key as the key
Value sessionstorage getItem('a')
Clear the value sessionstorage removeItem('a')
Empty sessionstorage clear()   
//Only clear the sessionStorage of the current application and obtain the sessionStorage of other sub applications 
    sessionStorage. Getitem (sub application name: + key)
localStorage AndsessionStorageequally

props communication

In the micro front-end applications built above, the communication between father and son is an extremely common and unavoidable demand, and qiankun certainly has consideration in this regard.

Parent application

In the main application portal / SRC / singlespa When registering a sub application in JS, pass the defined msg to the sub application through the props parameter.

// Define the data passed into the sub application
const msg = {
    data: {
      auth: false
    },
    fns: {
      portal_alert(txt) {
  
        // txt value passed by subapplication
  
        alert('Method of parent application:' + txt)
  
      },
  
      portal_logout() {
  
        parentThat.$store.dispatch('fedLogOut').then(() => {
  
          const fullPath = parentThat.$route.fullPath
  
          const path = fullPath ? `/portal-login?redirect=${fullPath}` : '/portal-login'
  
          parentThat.$router.push({ path })
  
          location.reload() // To re instantiate the Vue router object and avoid bug s
  
        })
  
      }
  
    }
  // Register subapplications
  
    registerMicroApps([
  
    {
  
      name: 'app1',
  
      entry: '//localhost:7771',
  
      render,
  
      activeRule: genActiveRule('/app1'),
  
      props: msg, // Pass the defined data to the sub application
  
    },
  
    ])

Sub application

In the sub application's main In the bootstrap function of JS, hang the functions in the received props parameters on the vue prototype for easy use. You can also get props in other exported life cycle functions and handle them according to your imagination.

export async function bootstrap (props = {}) {

  // console.log('sub-app1 loading ')

/ / the value passed by the parent application is mounted on the vue prototype

  Vue.prototype.parentData = {...props.data}

/ / mount the method passed by the parent application on the prototype

  Vue.prototype.parentFns = props.fns

  }

Topics: Javascript Front-end Vue.js