Use qiankun to build micro services

Posted by gillypogi on Tue, 08 Feb 2022 07:37:38 +0100

Use qiankun to build micro services

background

A WEB-based management system contains several separate modules, which are not coupled with each other. If they are placed in the same project and maintained by several people at the same time, it is not conducive to management. The launch of a single sub module will pose a great risk to the full launch of the whole project, and it is prone to code conflict

1, What is a micro front end

The micro front end is to split different functions into multiple sub applications according to different dimensions. These sub applications are loaded through the main application. The core of the micro front-end lies in disassembly. After disassembly, it will be closed!

2, Why use micro front end

  1. Technology stack independent
    The main framework does not restrict access to the technology stack of applications, and micro applications have full autonomy
  2. Independent development and deployment
    The micro application warehouse is independent, and the front and rear ends can be developed independently. After the deployment, the main framework automatically completes the synchronous update
  3. Incremental upgrade
    In the face of various complex scenarios, it is usually difficult for us to upgrade or reconstruct an existing system, and the micro front end is a very good means and strategy to implement progressive reconstruction
  4. Stand alone runtime
    The state of each micro application is isolated, and the runtime state is not shared

We can divide an application into several sub applications and package the sub applications into LIBS one by one. Load different sub applications when the path is switched. In this way, each sub application is independent, and there is no need to limit the technology stack! Thus, the problem of front-end collaborative development is solved.

3, qiankun framework

https://qiankun.umijs.org/zh

In 2018, single spa was born. Single spa is a JavaScript front-end solution for front-end micro service (there is no processing style isolation, js execution isolation) to realize route hijacking and application loading.

In 2019, based on single spa, qiankun provided a more out of the box API (single spa + sandbox + import HTML entry), which is independent of the technology stack and easy to access (as simple as i frame).

4, qiankun framework instance

Demo address: https://github.com/li1164267803/qiankun-demo
When viewing the demo, all three items should run, and then see the effect in the main service

Here, we intend to establish three projects for practical operation. One Vue project acts as the main application, and the other Vue and React applications act as sub applications

1. Create three apps

1) Create base

vue create qiankun-box

2) Create sub app 1

vue create qiankun-vue

3) Create sub app 2

cnpm install -g create-react-app
create-react-app qiankun-react
  • Three projects

    Base: Qiankun base sub application: Qiankun Vue, Qiankun react

2. Project configuration (main)

1) Qiankun base configuration

After the project is created, we first configure the main application Qiankun base and enter man JS file, in main JS. It should be noted that the entry configuration is the domain name and port of our two subprojects. We must ensure that the two character subproject runs on these two ports. Container is our container name, which is the node on which our sub application is mounted, which is equivalent to the app node in Vue project. activeRule is our activation path, Display different sub applications according to the path.

  • Introducing qiankun plug-in
 npm i qiankun -S
  • main.js configuration
// Introducing qiankun
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
  {
    name: "vueApp", // Application name
    entry: "//localhost:3001 ", / / the js in this html parsing will be loaded by default. The dynamic execution (sub applications must support cross domain) fetch
    container: "#Container ", / / container id
    activeRule: "/app/vue" // Route activated by route
  },
  {
    name: "reactApp",
    entry: "//localhost:20000",
    container: "#container",
    activeRule: "/app/react"
  },
]);
start();
  • After configuration, we go to the app of Qiankun base Vue file is used to write the page of the main application. Here I installed element UI to beautify the page
npm i element-ui -S

In main JS to introduce element UI:

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);
  • Modify app Component code of Vue
<template>
  <div id="app">
    <el-menu :router="true" mode="horizontal">
     <el-menu-item index="/home">
        <span slot="title">Home</span>
      </el-menu-item>
       <!--Reference other sub applications-->
      <el-menu-item index="/app/vue">
        <span slot="title">qiankun-vue</span>
      </el-menu-item>
      <el-menu-item index="/app/react">
        <span slot="title">qiankun-react</span>
      </el-menu-item>
    </el-menu>
    <router-view></router-view>
    <div id="container"></div>
  </div>
</template>
  • router.js code
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [
    {
        path: '/',
        name: 'Home',
        component: Home
    },
    {
        path: '/about',
        name: 'About',
        component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
    }
]

const router = new VueRouter({
    mode: 'history',
    // base: process.env.BASE_URL,
    base: '',
    routes
})

export default router

2) Subapplication Qiankun Vue configuration

  • main.js configuration
import Vue from 'vue'
import App from './App.vue'
import router from './router'

// Vue.config.productionTip = false

let instance = null
function render(props) {
  instance = new Vue({
    router,
    render: h => h(App)
  }).$mount('#qkApp'); //  Here is to mount it into your own html. The base will get the mounted html and insert it
}

if (window.__POWERED_BY_QIANKUN__) { // Add publicPath dynamically
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
if (!window.__POWERED_BY_QIANKUN__) { // Run independently by default
  render();
}

// The parent application loads the child application. The child application must expose three interfaces: bootstrap, mount and unmount
// The protocol of the sub component is ok
export async function bootstrap(props) {

};

export async function mount(props) {
  render(props)
}

export async function unmount(props) {
  instance.$destroy();
}
  • router.js configuration
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  base: '/vue',
  routes
})

export default router
  • Vue.config.js configuration

Create a new Vue under the root directory of the sub application config. JS file

module.exports = {
    lintOnSave: false,  // Turn off eslint detection
    devServer: {
        port: 3001,//The port here must be consistent with the child application port configured by the parent application
        headers: {
            //Because the internal requests of qiankun are fetch es to request resources, sub applications must allow cross domain
            'Access-Control-Allow-Origin': '*'
        }
    },
    configureWebpack: {
        output: {
            //Resource packaging path
            library: 'vueApp',
            libraryTarget: 'umd'
        }
    }
}

3) Subapplication Qiankun react configuration

  • Index. In src directory JS file
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

function render(){
  ReactDOM.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>,
    document.getElementById('root')
  );
}

if(!window.__POWERED_BY_QIANKUN__){
  render();
}

export async function bootstrap(){

}
export async function mount() {
  render()
}
export async function unmount(){
  ReactDOM.unmountComponentAtNode( document.getElementById('root'));  // Uninstall node
}
  • config-overrides.js configuration

First introduce react app rewired and modify the package JSON start command

npm install react-app-rewired

Modify package JSON start command

"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
  },

Then, configure dev and package, and create config overrides in the root directory js

module.exports = {
    webpack: (config) => {
        config.output.library = 'reactApp';
        config.output.libraryTarget = 'umd';
        config.output.publicPath = 'http://localhost:20000/'; 	//  This app has its own port number
        return config;
    },
    devServer: (configFunction) => {
        return function (proxy, allowedHost) {
            const config = configFunction(proxy, allowedHost);
            config.headers = {
                "Access-Control-Allow-Origin": '*'
            }
            return config
        }
    }
}

3. Attention

1) How to load a micro application on a routing page of the main application

The main application of the react + react router technology stack: just let the activeRule of the sub application contain the route of the main application.

Main application of Vue + Vue router technology stack:

For example, the main application needs to log in on the login page. After successful login, it will jump to the main background management interface, where sub applications can be displayed.

Modify the main application router js:

// If this route has other sub routes, you need to register another route and still use this component.
// In this case, there are sub routes, so we need to redefine the route of the main page later
const routes = [
    {
	    path: "/",
	    name: "Login",
	    component: Login
	  },
	  {
	    path: "/main",
	    name: "Main",
	    component: Main,
	    children: [
	      {
	        path: "/home",
	        name: "Home",
	        component: () => import(/* webpackChunkName: "about" */ "../views/Home")
	      }
	    ]
	  },
	  {
	    path: "/app/*", // Path for all sub applications
	    name: "Main",
	    component: Main
	  }
	]

Modify main application main JS file:

// The activeRule of the sub application needs to contain the routing path of the main application
import { registerMicroApps, start} from "qiankun";
registerMicroApps([
  {
    name: "vueApp", // Application name
    entry: "//localhost:3001 ", / / the js in this html parsing will be loaded by default. The dynamic execution (sub applications must support cross domain) fetch
    container: "#Container ", / / container id
    activeRule: "/app/vue" // Route activated by route
  },
  {
    name: "reactApp",
    entry: "//localhost:20000",
    container: "#container",
    activeRule: "/app/react"
  },
]);

start();

Modify main application main.vue Page code:

```javascript
// In main Vue calls the start function in the mounted cycle of this component. Be careful not to call it repeatedly.
<template>
  <div class="main-content">
    <el-menu :router="true" mode="horizontal">
     <el-menu-item index="/home">
        <span slot="title">Home</span>
      </el-menu-item>
       <!--Reference other sub applications-->
      <el-menu-item index="/app/vue">
        <span slot="title">qiankun-vue</span>
      </el-menu-item>
      <el-menu-item index="/app/react">
        <span slot="title">qiankun-react</span>
      </el-menu-item>
    </el-menu>
    <router-view></router-view>
    <div id="container"></div>
  </div>
</template>

<script>
import { start } from "qiankun";

export default {
  name: "Main",
  mounted() {
    if (!window.qiankunStarted) {
      window.qiankunStarted = true;
      start();
    }
  },
};
</script>

4. Solve the problem that vue devtools debugging function cannot be used in vue sub applications

Main of micro application JS must add the code for the test environment to start devTools

Write to render function

// Vue devtools debugging
  if (window.__POWERED_BY_QIANKUN__ && process.env.NODE_ENV === "development") {
    // Vue devtools just add the code here
    // After you create app
    window.__VUE_DEVTOOLS_GLOBAL_HOOK__.Vue = instance.constructor;
    let instanceDiv = document.createElement("div");
    instanceDiv.__vue__ = instance;
    document.body.appendChild(instanceDiv);
  }

In Vue config. JS

devServer: {
    hot: true,
    disableHostCheck: true,
    overlay: {
      warnings: false,
      errors: true
    },
    headers: {
      "Access-Control-Allow-Origin": "*" // Sub application must support cross domain
    },
}

Topics: Microservices qiankun