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
- Technology stack independent
The main framework does not restrict access to the technology stack of applications, and micro applications have full autonomy - 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 - 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 - 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
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 }, }