Micro front-end

What is # # #

The term “microfront-end” first appeared in 2016, which is to extend the concept of microservices to the front-end domain. Patterns emerge that break the front-end into smaller, simpler chunks that can be developed, tested, and deployed independently while still being treated as a single cohesive product to the customer. We call this technology a microfront-end. It is defined as: an architectural style in which independently delivered front-end applications form a larger whole.

At present, the mainstream trend of the front-end is SPA application (single-page application), but with the change of requirements and the increase of functions, the project will become bigger and bigger, and it is difficult to maintain, and the cost of upgrading to the most mainstream technology stack will become higher and higher, and eventually become a “monolith application”. The idea of a micro front end is to treat a website or application as a combination of functions of a separate team.

The micro front-end architecture is designed to solve the problem of unmaintainable application in a relatively long time span, when a single application evolves from a common application to a Frontend Monolith due to the increase and change of the number of people and teams involved. For developers: project split, for users: project integration

### Micro front-end architecture has several core values

  • Stack independent

    The main framework does not limit the technology stack of access applications, and microapplications have full autonomy

  • Independent development and deployment

    The microapplication repository is independent, and the front and back ends can be independently developed. After deployment, the main framework can automatically complete synchronous update

  • The incremental upgrade

    In the face of a variety of complex scenarios, it is usually difficult to upgrade or reconstruct the existing system completely, and the micro front end is a very good means and strategy to implement the gradual reconstruction

  • Independent run time

    State is isolated between each microapplication and run time state is not shared

### Problems with project bloat

  • Long compilation time
    • Poor development experience (slow hot loading)
    • High packaging cost (long packaging time, pull the whole body)
  • Teamwork issues
    • Code conflict
    • Version control

The new problem

  • Domain name problem
    • Module split too much, need independent deployment, operation and maintenance costs, domain name management

Advantages and disadvantages and performance

  • advantages
    • Unified entrance
    • The incremental upgrade
    • Simple, separate code base
    • Independent deployment
  • disadvantages
    • Architecture complex
    • Dependency duplication
  • performance
    • Applications such as: the main application is a vue, son is also a vue, vue | vue – the router | vuex reloading, solution to production environment to webpack repeat dependencies are not packaged, Integrating the common resource externals was only loaded once through the CDN and whether script tags were dynamically inserted in the Qiankun environment

# # # architecture diagram

Common application scenarios

  • Module and module interaction is not much, such as: several management systems merge permission menu to the main application rendering, unified system entrance, customer service panel, work order panel and other plug-in panels do not need to do a lot of interaction with other applications

####JS customer service panel

####JS worksheet panel

#### has a simple and clear structure

Implementation scheme

Open source framework for Qiankun Ali

single-spa

qiankun

How to use

The main application

import {
  start,
  initGlobalState,
  registerMicroApps,
  runAfterFirstMounted,
  // setDefaultMountApp,
  addGlobalUncaughtErrorHandler,
} from "qiankun";
import render from "./render";
import { MICRO_APP_LIST } from "@/config";

// Step1 initialize the application
render({ loading: false });

const loader = (loading) = > render({ loading });

// Microapplication configuration
const apps = MICRO_APP_LIST.map((app) = > {
  const { name, entry, activeRule } = app;
  const container = "#subapp-viewport";
  return {
    name,
    entry,
    activeRule,
    loader,
    container,
    props: { activeRule },
  };
});

// Step2 register the child application
registerMicroApps(apps, {
  beforeLoad: [
    (app) = > {
      console.log("[LifeCycle] before load %c%s"."color: green;", app.name); },].beforeMount: [
    (app) = > {
      console.log("[LifeCycle] before mount %c%s"."color: green;", app.name); },].afterUnmount: [
    (app) = > {
      console.log("[LifeCycle] after unmount %c%s"."color: green;", app.name); },]});const { onGlobalStateChange, setGlobalState } = initGlobalState();

onGlobalStateChange((value, prev) = > {
  console.log("[onGlobalStateChange - master]:", value, prev);
});

// Set the global status data
setGlobalState();

// Step3 set the default subapplication
// setDefaultMountApp('/cs');

// Step4 start the application
start({
  prefetch: "all".// Turn on strict style isolation, but it can also cause problems. For example, some UI frames are modally inserted into the body node
  // sandbox: { strictStyleIsolation: true }
});

runAfterFirstMounted(() = > {
  console.log("[MainApp] first app mounted");
});
Copy the code

# # # # application

import Vue from "vue";
import App from "./App.vue";
import router, { routes } from "./router";
import store from "./store";
import "./style.scss";
import "@/plugins";

// Solve the microapplication load resource 404 problem
// eslint-disable-next-line
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;

Vue.config.productionTip = false;

let instance = null;

function render(props = {}) {
  const { container } = props;

  instance = new Vue({
    router,
    store,
    render: (h) = > h(App),
  }).$mount(container ? container.querySelector("#app") : "#app");
}

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

export async function bootstrap() {
  //
}

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

export async function unmount() {
  instance.$destroy();
  instance.$el.innerHTML = "";
  instance = null;
}

// Export all routes of the micro-application for use by the main application
export const routes = allRoutes;
Copy the code

####vue.config.js

const {
  name: MICRO_APP_NAME,
  port: MICRO_APP_PORT
} = require("./package.json");
// TODO:Vue browser plug-in cannot be used when configuring chainWebpack and configureWebpack in the development environment
module.exports = {
  publicPath: ". /".productionSourceMap: false.runtimeCompiler: true.parallel: false.css: {
    sourceMap: false
  },
  configureWebpack: config= >{ config.output = { ... config.output,// Package the child application into the UMD library format
      library: `${MICRO_APP_NAME}-[name]`.libraryTarget: "umd".jsonpFunction: `webpackJsonp_${MICRO_APP_NAME}`
    };
  },
  devServer: {
    host: "0.0.0.0".open: true.port: MICRO_APP_PORT, // Ports need to be unified
    clientLogLevel: "warning".compress: true.inline: true.hotOnly: true.quiet: true.https: false.progress: true.disableHostCheck: true.headers: {// Enable resource cross-domain
      "Access-Control-Allow-Origin": "*"
    },
    overlay: false
  },
  lintOnSave: true
};
Copy the code

Communication plan

In the micro-front-end scenario, we believe that the most reasonable communication scheme is to deal with URL and CustomEvent. However, in some simple scenarios, the solution based on props is more straightforward and convenient, so we provided the users of Qiankun with a set of apis to complete the communication between applications:

Global variable isolation

class SnapshotSandbox {
    constructor() {
        this.proxy = window; / / window properties
        this.modifyPropsMap = {}; // Log the changes on the window
        this.active(); / / activation
    }
    active() {
        this.windowSnapshot = {}; / / photo
        for (const prop in window) {
            if (window.hasOwnProperty(prop)) {
                this.windowSnapshot[prop] = window[prop]; }}Object.keys(this.modifyPropsMap).forEach((p) = > {
            window[p] = this.modifyPropsMap[p];
        });
    }
    inactive() {
        / / the deactivation
        for (const prop in window) {
            if (window.hasOwnProperty(prop)) {
                if (window[prop] ! = =this.windowSnapshot[prop]) {
                    this.modifyPropsMap[prop] = window[prop];
                    window[prop] = this.windowSnapshot[prop];
                }
            }
        }
    }
}

let sandbox = new SnapshotSandbox();
// Execute immediately
((window) = > {
    window.a = 1;
    window.b = 2;
    console.log(window.a, window.b);
    sandbox.inactive();
    console.log(window.a, window.b);
    sandbox.active();
    console.log(window.a, window.b);
})(sandbox.proxy);

Copy the code

#### Project Structure

# # # noted

  • Configure runtime publicPath to solve the problem of microapplication loading resource 404webpack_public_path
    • webpack_public_path = window.INJECTED_PUBLIC_PATH_BY_QIANKUN;
  • The microapplication cannot be started because the port is occupied
    • The port configured in the vue.config.js subapplication must be the same as that configured when the primary application registers the subapplication.

###vue instance issue

The resources

  • An official example of Qiankun
  • Practice of micro front end scheme based on Vue technology stack
  • Micro front end in meituan takeout practice
  • Qiankun source code analysis