The micro front end appears in our sight more and more times, because the development of TO B is more and more rapid, resulting in a surge in the demand for background applications, how to set a number of projects into a Web main body has become a problem, of course, there are also many children will have doubts 🤔, what is the micro front end?

1. What is a micro front end

Micro front-end architecture scheme is essentially is a kind of project, in order to solve the front-end is too large, lead to problems in terms of project management in maintenance, team cooperation, upgrade iterations difficult questions, do not have a unified technology stack, and so on, are similar to the concept of micro service, is to expand the service concept to the front to develop an application, at this point you may be a face of meng force ~, we went on to speak

Take for example: 7 certain cloud platform

In essence, it should be a micro-front-end application. The menu on the left is the entrance of each sub-application. Switching the menu is switching the sub-application at the same time, and the whole main container is a portal (including user login mechanism, access to menu permissions, global exception handling, etc.).

2. Landing mode of the micro front end

Micro-front-end it applies the concept of micro-service to the browser end, that is, the Web application is divided from a single single application into multiple small front-end applications.

2.1 the iFrame

IFrame is one of the simplest ways to microfront-end integration. It can be said that iFrame pages are completely independent, and static resources (JS, CSS) in iFrame pages are isolated from each other without interference, equivalent to an independent environment, with sandbox isolation, so that front-end applications can run independently of each other

// Switch between different service items by switching urls <iframe v-show="url" frameborder="0" id="contentIframe"></iframe>
 createFrame(url) {
      const iframe = document.getElementById('contentIframe');
      const deviceWidth = document.body.clientWidth;
      // const deviceHeight = document.body.clientHeight;
      iframe.style.width = `${Number(deviceWidth) - 10}px`;
      iframe.style.height = `The ${800}px`;
      iframe.src = url;
}

Copy the code

Of course iFrame has limitations 👇 :

  • Subprojects need to be adjusted and navigation needs to be hidden in their own pages (public areas)
  • IFrame embedded view control is difficult and has limitations
  • The refresh does not save records, which means that when the browser refresh state disappears, the back return is invalid
  • Iframe blocks main page loading

2.2 Route Distribution Mode

Route distribution is implemented by dividing services into subprojects using routes and combining them with reverse proxy

Route distribution is also a relatively simple way to realize the micro front end, aggregating multiple sub-projects into one. Forwarding agents of different routes can be configured through NGXIN, as follows

http { server { listen 80; Server_name 192.168.0.1 location/web/monitor {proxy_pass http://192.168.0.2/web/monitor; } the location/web/admin {proxy_pass http://192.168.0.3/web/admin; } location / { proxy_pass /; }}}Copy the code

Different routing requests are forwarded to different project DNS servers. The advantages of this method are convenient teamwork, independent of the framework, and independent deployment and maintenance of projects

Of course, route distribution also has limitations:

  • Poor reusability between Web applications
  • Switch between each independent project, need to reload, easy to appear white screen affect user experience

2.3 Single – SPA

Officially billed as “a JavaScript front-end solution for front-end microservization,” Single-SPA sounds like a big deal: it works with a variety of technology stacks and can use multiple technology frameworks (React, Vue, Angular, etc.) on the same page. Forget about refactoring old project code for a new technical framework, official documentation 🚀

General principle is, first of all need a main application (containers), applications need to register first, and then when the url to match the corresponding application after routing, will first request application resources, and then mount application, in the same way, when the url routing, switching out the child application will uninstall the app, switch to the child the effect of application, Alternate between boostrap (get the output resource file), mount, and unmount through the subapplication life cycle

Talk about the advantages of single-spa:

  • Each project is developed, deployed and iterated independently with high efficiency
  • Development teams can choose their own technologies and keep the stack up to date.
  • Interdependence is greatly reduced
  • Benefit CI/CD, faster product delivery

As time is reserved for the ultimate boss, the practice of single-SPA is not covered in this article, but the following articles are for those who are interested

Front-end microservitization solution 2-single-SPA

2.4 Qiankun (Ant Financial Micro Front End Frame)

Qiankun is a single-SPa-based microfront-end implementation library that aims to make it easier and painless to build a production-ready microfront-end architecture system. Official documents 🚀

The name Qiankun is a good one, but it is essentially a encapsulation of the single-SPA mentioned in the previous section to make it easier for us front-end developers to use

  • Main application under installation of Qiankun
yarn add qiankun
Copy the code
  • How do I register a child application in the main application

The react method is described in the official document, while the Tree sauce method is developed based on VUE. Therefore, the vUE method is described here, which is essentially to register the subproject application (load the static resources compiled by the subproject on demand). When the subapplication is loaded, the browser URL changes. It will automatically trigger the routing matching logic of Qiankun to execute the sub-application’s life cycle function. The following is the specific implementation 👇

// modify import Vue from in main.js"vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import axios from 'axios';
import api from "./service";
import ViewUI from 'view-design';
import cacheKeys from '@/const/cacheKey';
import globalMixins from '@/mixin/global';
import Bus from '@/utils/bus';
import 'view-design/dist/styles/iview.css';
import './theme/customTheme.less';
import '@/icons';

Vue.config.productionTip = false; Import {registerMicroApps, runAfterFirstMounted,setDefaultMountApp,
  start
} from "qiankun"; Import {genActiveRule} from"./utils"; // Import LibraryJs from"./library/js"; // Import the emit function import * as childEmit from from the main application"./utils/childEmit"// Define the data that is passed to the child application vue. mixin(globalMixins); Vue.use(ViewUI); Vue.use(api); Vue.use(Bus); Vue.prototype.$axios = axios;
Vue.prototype.$cacheKeys = cacheKeys;
Vue.config.productionTip = false; // Define the data passed to the child applicationletMSG = {data: store, // components: LibraryUi, // utils: LibraryJs, // emitFnc: Prototype: [{name:'$axios', value: axios },
    {name: 'isQiankun', value: true},// If qiankun is enabled]}; // The main application render functionlet app = null;
function render({ appContent, loading } = {}) {
  if(! app) { app = new Vue({ el:"#container",
      router,
      store,
      data() {
        return {
          content: appContent,
          loading
        };
      },
      render(h) {
        returnh(App, { props: { content: this.content, loading: this.loading } }); }}); }else{ app.content = appContent; app.loading = loading; } window.vue = app; }; render(); // Register child application registerMicroApps([{name:"monitor",
      entry: "http://10.0.0.110:8081/",
      render,
      activeRule: genActiveRule("/monitor"),
      props: msg
    },
    {
      name: "portalAdmin",
      entry: "http://183.62.46.202:8082/",
      render,
      activeRule: genActiveRule("/admin"),
      props: msg
    }
  ],
  {
    beforeLoad: [
      app => {
        console.log("before load", app);
      }
    ],
    beforeMount: [
      app => {
        console.log("before mount", app);
      }
    ],
    afterUnmount: [
      app => {
        console.log("after unload", app); }}],); // Set the default child applicationsetDefaultMountApp("/portal"); RunAfterFirstMounted (() => {// console.log(app)}); // start({prefetch:true });

/* new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app"); * /Copy the code
  • Subapplication adaptation

The sub-application does not need to install any additional dependencies to connect to the Qiankun master application, simply exposing the corresponding lifecycle hooks to the master application

import Vue from 'vue';
import VueRouter from 'vue-router';
import routes from './router';
import './public-path'; // Declare variables to manage vue and routing instanceslet router = null;
letinstance = null; // Export the child application life cycle before mountingexport async functionbootstrap(props = {}) { Vue.prototype.isQiankun = props.isQiankun; } // Export the child application life cycle before and after mountingexport async function mount({data = {}} = {}) {
  router = new VueRouter({
    base: window.__POWERED_BY_QIANKUN__ ? '/portal' : '/',
    mode: "history",
    routes
  });
  window.vue = instance = new Vue({
    router,
    store,
    render: h => h(App, {props: data})
  }).$mount("#app"); }; // Export the sub-application lifecycle before mounting and after unmountingexport async function unmount() {
  instance.$destroy(a); instance = null; router = null; } / / a single development environment window. __POWERED_BY_QIANKUN__ | | the mount ();Copy the code

The child application is mounted to the main application using props

You also need to introduce the public-path.js file to main.js

// public-path.js 
if (window.__POWERED_BY_QIANKUN__) {
  // eslint-disable-next-line no-undef
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
Copy the code

After the lifecycle hook function is configured, to enable the main application to obtain the resource files exposed by the child application, the child application packaging tool needs to add the following configuration:

// vue.config.js

module.exports = {
  resolve: {
            alias: {
                The '@': resolve('src'),
            },
    },
   configureWebpack: {
    output: {
      library: `${name}-[name]`,
      filename: '[name].js',
      libraryTarget: 'umd',
      globalObject: 'this',,}}}Copy the code

The above is the completion of the micro front-end adaptation of the child and parent application, the process may encounter some strange problems, you can check the official see problems and github issue

After completing the above steps, you will need to configure Nginx when you want to deploy to a test or production environment.

Let’s start with the nginx configuration of the child application

events {
    worker_connections  1024;
}
http{
    server {
        listen       80;
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Headers X-Requested-With;
        add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
        location / {
            try_files $uri $uri/ /index.html; root /usr/share/nginx/html; index index.html index.htm; }}}Copy the code
  • Vue routing mode: The routing mode of the subproject is history, so it needs to be configured by Nginxtry_files $uri $uri/ /index.html;Otherwise, 404 will be reported when you refresh the routeVue official document
  • Cross-domain resource problem: The access source needs to be set. If the access source is not set, the primary application cannot obtain the resources (JS and CSS) of the sub-application.

After configuring the sub-application, the ngniX of the main application should not be missed

http{
    server {
        listen       80;
        location / {
            try_files $uri $uri/ /index.html;
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
        location /monitor {
           try_files $uri $uri/ /index.html;
           proxy_pass http://10.0.0.110:8081;
        }
        location /admin {
            try_files $uri $uri/ /index.html; Proxy_pass http://183.62.46.202:8082; }}}Copy the code

You’re done

3 summary

3.1 Some quality micro front end articles to share

Probably the most complete microfront-end solution you’ve ever seen

Microfront-end architecture selection guide

Daily Youxian supply chain front end team micro front end transformation

Alili. Tech micro front end

Micro-frontend Architecture in Action- things like that

Welcome to point out the problem 🧒