The micro front end is a very hot concept these days, and the community actually has quite a few mature solutions to implement it. As a heavy user of UMI, I had to experience The Qiankun developed by Ali based on Single-SPA. The best combination of UMI and Qiankun is undoubtedly the plug-in @Umijg/plugin-Qiankun tailored for Umi. Let’s follow the documentation on the official website.

The Demo implementation

Create a project

  1. npx @umijs/create-umi-app
  2. npm install
  3. npm install @umijs/plugin-qiankun --save
  4. npm start

Create three projects, one as the main application and two as child applications

Configuring the Master Application

  1. Register child applications. In the main application. Umirc. Ts, enable qiankun. This is a way to open the UMi3 plug-in, as long as the plug-in key has the corresponding configuration will be opened.
export default {
  qiankun: {
    master: {
      // Register sub-application information
      apps: [{name: 'app1'.// Unique ID, which must be the same as name in package.json in the microapplication
          entry: '//localhost:8001'.// html entry
        },
        {
          name: 'app2'.// Unique ID, which must be the same as name in package.json in the microapplication
          entry: '//localhost:8002'.// html entry}],},},};Copy the code
  1. Load the child application. You can bind the route to the subapplication by setting the microApp attribute to the name of the subapplication
export default {
    routes: [{path: '/'.component: '.. /layouts/index.js'.routes: [{path: '/app1'.microApp: 'app1'.// Configure the Loading property
           microAppProps: {
            autoSetLoading: true.className: 'myContainer'.wrapperClassName: 'myWrapper',}}, {// app2
          // ...}],},],}Copy the code

Configuring subapplications

  1. Plug-in registration. inpackage.jsonIn the configuration"name": "app1". Also need to configure.umirc.ts file to open qiankun.
export default {
  qiankun: {
    slave: {}}}Copy the code
  1. Environment variable configuration. in.envIn:
PORT=8001
HMR=none
Copy the code

If you encounter an error due to dev scripts port number, you can disable HMR first

  1. If the child application needs to add some custom logic to its life cycle, it needs to be in thesrc/app.tsExport an object fromqiankun
export const qiankun = {
  // Before the application loads
  async bootstrap(props) {
    console.log('app1 bootstrap', props);
  },
  // Apply render before trigger
  async mount(props) {
    console.log('app1 mount', props);
  },
  // Triggered after the application is uninstalled
  async unmount(props) {
    console.log('app1 unmount', props); }};Copy the code

Now run three projects, can through the main application to access the application, visit http://localhost:8000/app1 for example shows the application page. Note that if the port number of the subapplication is _8001_, the back-end requests under the same domain name sent by the original subapplication are also on _8001_ port. However, if the primary application accesses the request, the back-end requests are changed to _8000_ port. Proxy forwarding is required, and you can configure proxy in. Umirc.

At this point, the applications are basically independent, and we need to add global state of supply communication between users

Interapplication communication

The useModel of @umijs/plugin-model is used primarily to globalize the data. Umi should already have the @umijs/ preset-React plugin set built in, including @umijs/plugin-model

Primary application production data

In SRC /app.ts, export a function, useQiankunStateForSlave, which returns content injected into the props and passed to the child application. The setXXX method returned by useState should not be named setGlobalState, otherwise it will be overwritten by another function of the same name in the mount phase.

// src/app.ts
export function useQiankunStateForSlave() {
const [globalState, setQiankunGlobalState] = useState({ str: 'aaa'})

  return {
    globalState,
    setQiankunGlobalState
  };
}
Copy the code

If the main application also needs to use the globalState, you can also access @@qiankunStateForSlave with useModel in the component:

const { globalState } = useModel('@@qiankunStateForSlave');

Subapplications consume data

The child application accesses @@QiankunStateFromMaster via useModel to get the props passed from the main application

export default() = > {const masterProps = useModel('@@qiankunStateFromMaster');

  useEffect(() = > {
    masterProps.setQiankunGlobalState({ str: 'bbb'}}), [])return (
    <p>{JSON.stringify(masterProps.globalState)}</p>
  );
}
Copy the code

In this way, the master application is responsible for managing globalState, and the child application can take globalState and call methods on masterProps to tell the master application to modify globalState

The Demo presentation

Child app App2 changes the globalState of the main app from AAA to BBB

Some think

How do I manage application permissions

Each background system, basically is the need to obtain user rights to restrict access to some pages. In the micro-front-end scenario, it is better for the main application to manage the user permissions of each sub-application in a unified manner. It would be nice to leave the logic of accessing the child application alone unchanged.

Assuming the token is placed in localStorage, two scenarios come to mind:

  1. [Unified processing] Once entering any sub-application, the master application takes out the token and sends a checkLogin request. The backend checks the login status of the two sub-applications, and the login logic will be triggered as long as any of the two sub-applications are not logged in. If both of them are logged in, the userInfo of the two sub-applications will be returned. (Need back-end plus interface support)
  2. [Separate processing] Once entering any subapplication, the master application takes out two tokens and sends two checkLogin requests, which are forwarded to the domain name of the subapplication. The two back ends of the subapplication check the login state respectively, and return userInfo if any. As long as the primary application does not receive two copies of userInfo, it triggers the login logic and passes userInfo to the child applications.

The sub-application identifies whether it is in the master application based on the current domain name. If yes, the sub-application does not use its own login verification logic.

Can Umi2 be supported?

I also tried to access umi2 version of the project, namely according to the corresponding version of the Qiankun plug-in

npm install @umijs/plugin-qiankun@umi2 --save

And it works

This version of the plugin does not use @@QiankunStateForslave to get masterProps. This version uses const masterProps = useRootExports() to get masterProps. Obviously, the main application has to deal with the extra global state for the UMi2 child application, which feels inconvenient.

The resources

Umi website @ umijs/plugin – qiankun

🏆 technology project stage 4 | chat micro front end of those things…