The background,

Due to the continuous expansion of the company’s business, the original background management system became more and more bloated, and it took several minutes to run packaging every time, which greatly delayed the development and debugging time. At the beginning, the project was unpacked according to the business, and all the projects were placed in the same folder on the server. The parent project mounted its instance, routing, state management, etc., under the Window for the sub-projects to use, and the father and son projects shared the instance. In production mode, the parent project will read the HTML files of other sub-projects and load the corresponding JS and CSS files. In local debugging mode, each sub-project will read the index.html of an environment parent project as its own template to run. The downside of this approach is that sub-projects cannot be run and released independently, so the company uses a micro front end when building new projects.

Two, micro front end

Microservices are a variant of service-oriented architecture (SOA) that designs applications as a series of loosely coupled fine-grained services organized by lightweight communication protocols, specifically building applications as a set of small services. Each of these services can be deployed and extended independently, with solid modular boundaries that allow different services to be written in different programming languages and managed by different teams.

When the company has more and more business requirements, the project will be bigger and bigger. It is very difficult to reconstruct the project in the future or to separate a large business requirement. Or with a new and better technical framework, it is also difficult to transform the previous project. In this case, the advantages of the micro front end are obvious. The key advantages of breaking the huge block into small pieces and dividing and ruling are:

  • Technology stack independent main framework does not limit access to the application stack, microapplications have full autonomy
  • Independent development, independent deployment of micro application warehouse independent, the front and back end can be independently developed, after the deployment of the main framework automatically complete synchronization update
  • Incremental upgrade In the face of a variety of complex scenarios, it is usually difficult to upgrade or reconstruct the existing system technology stack completely, and the micro front end is a very good method and strategy to implement the incremental reconstruction
  • Independent run time States are isolated between each microapplication and run time states are not shared

In this paper, qiankun was used to realize the micro front end.

Third, qiankun

Qiankun is a productionable micro-front-end framework based on Single-SPA, with JS sandbox, style isolation, HTML Loader, preloading and other capabilities required by micro-front-end systems. The Qiankun can be used with any JS framework and microapplication access is as simple as embedding an IFrame system.

Next, the micro front end based on Qiankun is simply constructed.

Four, the practice

First, create two VUE projects, one for the main application and one for the micro application.

The main application

Next we transform the main application first:

1. Install Qiankun

yarn add qiankun
Copy the code

2. Register microapps with the main app

First, add the micro directory under the SRC directory, and add app.js to store the micro-applications that need to be registered.

src/micro/app.js

const getActiveRule = (hash) => (location) => location.hash.startsWith(hash);
const apps = [
    {
        name: 'sub-app1',
        entry: '//localhost:8081',
        container: '#sub-container',
        activeRule: getActiveRule('#/sub1')
    }
]
export default apps
Copy the code
  • name – stringN/A Mandatory. This parameter is mandatory. Each micro-application must be unique.
  • entry – string | { scripts? : string[]; styles? : string[]; html? : string }– Mandatory, micro application entry.
    • If the value is a string, it indicates the access address of the micro-application. In the preceding example, only the local access address is configured. In actual projects, you need to configure the access address of the micro-application based on the environment.
    • When configured as an object,htmlThe value of is the HTML content string of the microapplication, not the access address of the microapplication. The application of micropublicPathWill be set to/. (This method has not been tried, interested partners can try ~)
  • container – string | HTMLElement– Mandatory, micro – application container node selector or Element instance. The example above represents the container node with id ‘sub-container’, which can also be written ascontainer: document.querySelector('#sub-container').
  • activeRule – string | (location: Location) => boolean | Array<string | (location: Location) => boolean>N/A Mandatory: Specifies the activation rule for the micro application.
    • Support for configuring strings or arrays of strings directly, such as activeRule: ‘/sub1’ or activeRule: [‘/sub1’, ‘/sub2’],

    • You can configure an active function or a group of active functions. The function takes the current location as an argument, and returns true to indicate that the current microapplication is activated. Such as location = > location. The pathname. StartsWith (‘/app1)

      This article is in hash mode, so write activeRule: getActiveRule(‘#/sub1’). You can also write activeRule: ‘#/sub1’ directly, but this will not work if the main application is in history mode or deployed in a non-root directory.

  • loader – (loading: boolean) => void– Optional. This method is called when the loading state changes.
  • props – object– Optional. Data that the master application needs to pass to the microapplication. It can be used for inter-project communication.

Next, add index.js under Micro to register our micro application

src/micro/index.js

import { registerMicroApps, addGlobalUncaughtErrorHandler, start, } from "qiankun"; import apps from './app' registerMicroApps(apps, { beforeLoad: (app) => { console.log('before load', app.name) return Promise.resolve() }, afterMount: app => { console.log("after mount", app.name); return Promise.resolve() } }) addGlobalUncaughtErrorHandler((event) => { console.error(event, 'event'); const { message: MSG} = event if (MSG && msg.includes("died in status LOADING_SOURCE_CODE")) {console.error(" died in status LOADING_SOURCE_CODE"); }}); export default start;Copy the code

registerMicroApps(apps, lifeCycles?)

  • apps – Array<RegistrableApp>– Mandatory. Some registration information about the micro application.
  • lifeCycles – LifeCycles– Optional, global microapplications declare periodic hooks.

This API is the basic configuration information used to register microapplications. When the browser URL changes, it will automatically check the activeRule rule registered for each micro-application, and the application that meets the rule will be automatically activated.

addGlobalUncaughtErrorHandler(handler)

  • handler – (... args: any[]) => void– will choose

This API is used to add global uncaught exception handlers.

start(opts?)

  • opts – Options– optional

The API is used to launch Qiankun.

3. We need to upgrade our app. vue first by adding a node with the ID of “sub-Container”

src/App.vue

< template > < div > < div id = "nav" > < the router - link to = "/ home" > home < / router - the link > | < the router - link to = "/ sub1" >) < / router - the link > </div> <div id="sub-container"></div> <router-view /> </div> </template> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; } #nav { padding: 30px; } #nav a { font-weight: bold; color: #2c3e50; } #nav a.router-link-exact-active { color: #42b983; } </style>Copy the code

Then you need to modify main.js and execute the startup function. `

src/main.js

import { createApp } from "vue"
import App from "./App.vue"
import router from "./router"
import start from "./micro"

const instance = createApp(App).use(router).mount("#app")

instance.$nextTick(() => {
    start()
})
Copy the code

One thing to note above is that the start function must be called after the DOM node is loaded, otherwise the container DOM will not be found. You can see the common problems in detail.

Now that our main application is built, we can build the micro application.

Micro application

The microapplication does not require any additional dependencies to be installed to access the Qiankun master application.

1. Add the public-path.js file in the SRC directory to modify the publicPath of the runtime.

if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
Copy the code

We need to import the newly added public-path.js file and export the bootstrap, mount, and unmount lifecycle hooks for the main application to call at the appropriate time.

import "./public-path" import { createApp } from "vue" import App from "./App.vue" import router from "./router" // Let instance = null function render(props) {const {container} = props instance = createApp(App) instance .use(router) .mount(container ? container.querySelector("#app") : "#app")} /** * Bootstrap will only be called once during the micro-application initialization. The next time the micro-application re-enters, the mount hook will be called directly. Bootstrap will not be triggered again. * This is usually where we can initialize global variables, such as application-level caches that will not be destroyed during the unmount phase. */ export async function bootstrap() {console.log("VueMicroApp bootstraped")} /** * The mount method is called every time the application is logged in, */ export async function mount(props: Any) {console.log("VueMicroApp mount", props) render(props)} */ export async function unmount() {console.log("VueMicroApp unmount", Instance.unmount ()} // If (! window.__POWERED_BY_QIANKUN__) { render() }Copy the code

The important thing to note here is that in order to avoid conflicts between the root id#app and the rest of the DOM, you need to limit the search scope. If you use the root ID directly, the following error will be reported:

Application died in status NOT_MOUNTED: Target container with #container not existed after xxx mounted!

3. Package configuration modification

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

vue.config.js

const path = require("path"); Module. exports = {devServer: {// listener port: 8081, // disableHostCheck so that micro applications can be fetched disableHostCheck: Headers: {" access-Control-allow-origin ": "*",},}, configureWebpack: {output: headers: {access-Control-allow-origin: "*",},}, configureWebpack: {output: Library: "sub-app1", // Expose your library in a way that works for all module definitions. JsonpFunction: 'webPackJsonp_sub-app1',},},};Copy the code

4. Modify the route

Prefixes the microapplication route with the same value as the activeRule we configured for the microapplication in the main application.

import { createRouter, createWebHashHistory } from "vue-router"

const routes = [
  {
    path: "/",
    name: "sub1",
    component: () => import("../views/sub1.vue")
  }
]

const microAppPrefix = "/sub1"
const setRoutesMicroAppPrefix = routes => {
  if (routes.length) {
    routes.forEach(item => {
      if (item.path && item.path.indexOf(microAppPrefix) === -1) {
        item.path = `${microAppPrefix}${item.path}`
      }
      if (item.children && item.children.length) {
        setRoutesMicroAppPrefix(item.children)
      }
    })
  }
}

if (window.__POWERED_BY_QIANKUN__) {
  setRoutesMicroAppPrefix(routes)
}

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

export default router

Copy the code

The microapplication is all configured, let’s see the effect ~

5. Refer to the article

1, qiankun