Understanding the microfront end

Micro front end is a very hot topic recently, the front end is like falling in love, it is really “a long time will be divided, a long time will be closed”. The micro front end is not a show-off, it’s a solution.

The development history of micro front end

For example, the company has many internal systems, such as human resources system, financial system, time management, project management, forum and so on. When a new employee joins the company, it is difficult for him to remember all the addresses in a short time.

If the address is not too many, the browser bookmarks can be remembered, but when the address changes (for example, old and new versions exist at the same time), the local bookmarks will not work.

To solve this problem, different periods of practice:

Early: the more common approach is to do a website navigation, which can solve the problem of too many addresses to remember, as well as the problem of address change, but the switch between the system is not very friendly, have to return to the navigation page to switch. For example hao123.

Middle stage: put the url navigation in the upper left corner of each system and click to bring up the url navigation menu. Then the url navigation separately made a JS, maintenance of a, all systems shared, the disadvantage is that the system switch needs to refresh the page, and there are too many things repeated loading. For example, Ali Cloud Control console.

Later stage: it is divided into the master sub-system, the site navigation and the main system at the top/bottom of the page, without repeated loading, the content area presents the subsystem with IFrame, click the navigation, only switch the content, not refresh the page. This is the prototype of a micro front end.

When should you use a micro front end

  1. When a project introduces other projects (together)

Some legacy items (or maintenance items) can also be used without major changes and need to be integrated together.

For example, when some functions/pages of one system already exist in another system and need to be reused, a micro front end can be considered.

  1. When your project is huge (points)

Of course, the definition of “big” is very vague. What is it, and how should it be broken down? It depends on the circumstances

For example, you are working on a “human Resource Management system”, which has many modules: personnel files, onboarding and exit promotions, attendance, performance, compensation, social security, training, recruitment, etc. Now you have a client that only needs a few of these modules and needs the source code.

Buy all the features. Customers don’t want to pay that much. Give me the whole code. The company’s losing money again. Of course, it’s possible to pick the code that the customer needs, but if you have more than one of these customers, you’re going to have to do a lot of useless work.

If the project can be divided into a basic function and N additional functions, each function into an independent system, independently developed and deployed, so that the free combination of sales, the company and customers are happy.

Situations where the micro front end is not applicable

The project is very large, but there is no need for free combination sales. When refactoring is required, technology selection (Vue, React, Angular) is preferred, and micro front-end is not recommended.

Even if a project has hundreds of pages, as long as it is properly managed, well documented, well automated and engineered, it can still iterate well.

Common microfront-end scenarios

The various micro-front-end solutions on the Internet look very cool, and the terms are also very fancy, but in fact they are the same. Only iframe and Sing-SPA (based on single-SPA) are reusable solutions that can actually reach production. Same idea, different details.

The core of microfront-end technology is loading and execution. In addition to the iframe scheme, there are three loaded schemes: JS Entry, HTML Entry, and Config Entry. Executing files is cumbersome and not a simple script/style tag (although it can be used, it is not a mature solution because of js/ CSS contamination).

iframeplan

Iframe has always played an important role in the development of the front-end:

Loading across HTML pages: Iframe is one of the solutions for moving from multi-page applications to single-page applications (clicking on the menu without refreshing the page). Later, the rise of three frameworks, iframe gradually faded out of view.

Cross-system loading: Iframe is the native solution provided by browsers when loading another system from one system. It is easy and easy to use, so it is also a micro-front-end solution.

The iframe solution has few problems other than poor user experience, with perfect JS/CSS isolation and no need to solve resource loading problems. Iframe is also a good choice for a micro front end, as long as your boss doesn’t have a problem with it and your customers accept it.

The threshold for iframe is low, but if you want to improve the scheme, the effort and the reward are not proportional. There are so many problems to optimize (see the link at the end of this article for details).

If HTTP is used, iframes cannot access their own cookies if they are cross-site with the host system. This is a very limited system (more on this in a moment).

single-spaplan

Single-spa does very little: it defines the subproject lifecycle (initialization, load, unload, update), subsystem state, and associated routing with subproject load/unload timing, error catching, and so on.

However, what the subprojects do in each life cycle, and how the resources of the subprojects are loaded and executed, and how the subprojects are unloaded, all need to be done by themselves.

Fortunately, there are plugins to help us do this:

  1. single-spa-vue/ (single-spa-react): Load and unload functions for subprojects
  2. systemjs-webpack-interop: Modifies the loading path of resources
  3. vue-cli-plugin-single-spa: Fix somethingwebpackPackaging configuration
  4. sysyem.jsLoading:jsResources and common plug-ins

A single SPA microfront-end loading process can be implemented with these four plugins:

Since single-SPA needs to judge subitems based on the location of the page, using different values (hash or path) to judge can have different effects on different subitems. How to choose a basis for judgment, and how to eliminate these effects, can you see this: Hash vs. history of the main project route

While this would allow for a microfront end, it felt like a patchwork of microfronts, every step of the way very clever. For example, the CSS of the subproject is packaged into JS and splitChunks are removed so that the subproject only has one app.js to load and execute.

For more complicated projects, it is very difficult to use single-SPA, and many things need to be solved by ourselves. For example:

  1. js/cssPollution problem;
  2. subprojectshtmlIn the otherjs/cssFile, you need to manually load;
  3. Only the parent project passes the value to the child project, and the communication between projects needs to be written by itself.
  4. Packaging deployment is troublesome;

Official online examples of single-SPA: Single-SPa-examples

qiankunplan

Qiankun was intended to be as simple and easy to use as Iframe, but the user experience was much better than iframe.

On the basis of single-SPA, Qiankun did these things:

  1. Solved the subproject loading problem by giving only one entry
  2. increasedjs/cssSandbox (To be honest, there is no perfect sandbox that will accommodate all situations).
  3. Added pre-request
  4. Increased two-way communication between projects
  5. Manual loading of subprojects is supported

In this way, the subprojects need to be packaged and deployed in a single copy that can be accessed independently and integrated by the main project, with few changes to the subprojects.

Qiankun is easy to get started with, but difficult to resolve, especially plug-in conflicts caused by the JS sandbox. It is recommended to understand the principles of Singles – SPA and sandbox first.

Advanced usage of the Qiankun scheme:

  1. The main project and subprojects share dependencies
  2. qiankunThe nested
  3. Subproject implementationkeep-alive

These have been covered in previous articles (link at the end)

Microfront-end pain points: IntractablecssIsolate the problem

This is mainly referring to the Qiankun and single-SPA schemes.

If only one child application is running at the same time, CSS contamination between sub-projects can be easily resolved:

  • single-spaYou can modify itbodyclassThe subproject will write the style to thisclassLet’s do it inside.
  • qiankunThe subproject is removed by subproject unloadstyleLabel solution.

However, style contamination between the main application and its children, as well as CSS contamination when multiple children are running at the same time, is difficult to solve.

Qiankun made a lot of new attempts on CSS pollution:

  1. shadow domTo isolate (sandbox : { strictStyleIsolation: true }Open)

If you are not familiar with shadow DOM, check out the introduction to MDN. To be honest, shadow DOM isolation works pretty well, similar to iframe. But it brings new problems:

  • Dom is blocked, so the subproject cannot get the root node

    Solution: The subproject finds the root node from the container, not the Document

    function render({ container } = {}) {
      // omit irrelevant content
      instance = new Vue({
        router,
        store,
        render: h= > h(App),
      }).$mount(container ? container.querySelector('#app') : '#app');
    }
    Copy the code
  • Because react click events are document proxies, shadow DOM will cause document to be unable to access the DOM of the subproject, resulting in invalid click events: github.com/facebook/re…

Solution: react-shadow-dom-retarget-events

  • Popover styles from append to body do not work: Most popovers do not append to body, but opening another Popover (i.e., nested popovers) in a Popover requires append to body. Popover is mandatory.

  • Compatibility issues: Shadow DOM is supported by Firefox (as of version 63), Chrome, Opera, and Safari by default. The new Edge based on Chromium also supports Shadow DOM; The old Edge didn’t survive long enough to support this feature

  • Font file for subproject does not take effect, display exception

  1. Wrap the styles of the subitems in a special selector. (sandbox : { experimentalStyleIsolation: true }Open)

All styles will be wrapped in the container. This is an experimental feature and is not recommended for production. The effect is as follows:

// div[data-vue-hash ="app-vue-hash"
div[data-qiankun="app-vue-hash"] .app-main {
  font-size: 14px;
}
Copy the code

The problem with this scenario is that the append to Body element style does not work.

Both of these solutions are not perfect, and CSS contamination is a matter of specification: in a VUE project, every component is scoped and global styles have a special class name/prefix, but this way, it doesn’t matter whether there is a CSS sandbox or not, and CSS contamination is avoided at the root.

Derivative requirements for microfrontend: cross-project component sharing

For component sharing between projects, private NPM is fine. However, if the project’s technology stack is different, for example, if you want to use vUE components in a React project, the NPM package can be more difficult.

Learn from the micro front end:

  1. projectAIn the entry fileexportThe function instantiated by this component
  2. projectAPackaged inumdFormat, and willcssPackaged injsTo remove thechunk-vendors.js.
  3. Packaging projectAtheapp.jsIntroduction to the projectBIn, call the instantiation function

The specific code is as follows:

Entry documents for Project A:

import Vue from 'vue';
import HelloWorld from '@/components/HelloWorld.vue'
import store from './store';
import i18n from './i18n';
// If this component does not use global plug-ins such as Store and i18n,
// Export this component directly from the vUE stack:
// export HelloWorld;
// Register directly when using:
// components: {
// HelloWorld: window['app-vue-hash'].HelloWorld
// },
export const createHelloWorld = container= > {
  return new Vue({
    store,
    i18n,
    render: h= > h(HelloWorld),
  }).$mount(container);
}
Copy the code

Package configuration for Project A:

module.exports = {
  publicPath: 'http://localhost:8080/'.css: {
    extract: false
  },
  // Customize the WebPack configuration
  configureWebpack: {
    output: {
      library: `app-vue-hash`.libraryTarget: 'umd'.// Package the child application into the UMD library format}},chainWebpack: config= > {
    config.optimization.delete('splitChunks')}};Copy the code

Project B uses this component:

<div id=appVueHash></div>
<script src=http://localhost:8080/js/app.js></script>
<script>
    window['app-vue-hash'].createHelloWorld('#appVueHash')
</script>
Copy the code

Notes:

  1. This component must be routing-independent because the route instance when invoked is not the same as the route instance when the component is instantiated.
  2. If there are parameters you need to pass to the component, write them in detailrenderFunction.
  3. This component needs to be destroyed manually, as returned by the function callvueInstance, directly called$destroyCan.
  4. This component and its descendants need to pass the prefix that references the resourcepublicPathSettings, which can also be dynamically modified and ignored if no resource is referenced.

You can optimize it even further: mount this component directly to the Window, and you don’t need to package the UMD.

window.createHelloWorld = container= > {
  return new Vue({
    store,
    i18n,
    render: h= > h(HelloWorld),
  }).$mount(container);
}
Copy the code

Package the configuration without configureWebpack and use it simply: window.createHelloWorld(‘#appVueHash’).

Similarly, the sub-project of Qiankun can be written in the same way, allowing the parent project to get the life cycle function.

How to select the micro front end solution

Don’t think that if you pass the official demo of Qiankun, you can use it directly. Actual projects can be N times more complex than that, and every difference creates new problems.

So it often happens that the sandbox opens and the project runs (a bunch of errors); Don’t open the sandbox, js/ CSS pollution is very serious. Even the local runs fine, but the deployment doesn’t (which is relatively easy to fix).

Think about two things before choosing Qiankun:

  1. Whether the project’s resources load correctly

    • If the project is useful to Webpack

      Make sure: modify the publicPath of webpack, can solve all resource loading problems, see vuE-cli3 introduction: HTML and static resources.

      Simple judgment: whether the resource files (except js/ CSS) are placed in the static directory (vue-cli2) or public directory (vue-cli3).

      Accurate judgment: Unblock the publicPath of Webpack with the address of server A, package it, put index.html on server B, put all other resources on server A (remember to allow cross-domain), and access the project (server B’s address). See if it is normal (simulated qiankun loading).

    • If the project doesn’t have Webpack, such as the jQuery project.

      • If the resources are placed in the CDN, or the links of resources are complete URLS, it can be trusted to boldly access.

      • If the resources are linked relative to each other, this solution can solve the problem of loading resources in the old jQuery project. If not, then we should be careful.

      • For jQuery multi-page applications, iframe is preferred

  2. Js/CSS contamination is difficult to resolve

    • After modularization, JS pollution problem is almost less, and JS sandbox is more perfect, even if there is a problem, is plug-in conflict between plug-ins, easier to solve

    • There is no good standard for determining whether CSS is contaminated or not. For vue, if all component styles are scoped, 99% of contamination is avoided. The rest of the global styles, if they all use special class/ ID, are perfect, with or without a sandbox. The ideal is rich, the reality is brutal, and if the project is all global, think again.

If both of these questions are OK, you can try using Qiankun.

Finally, there is no perfect solution. If there is a problem, don’t panic. Iframe can also be a perfect solution if you take the time.

The appendix

I have recorded my process of technology selection from IFrame to single-SPA and then to Qiankun, as well as some pits. If you are interested, you can understand:

  • Implementing a front-end microservice from 0 (part 1)
  • Implementing a Single-SPA front-end Microservice from 0 (middle)
  • Implementing a Single-SPA Front-end Microservice from 0 (part 2)
  • Practice and summary of Qiankun micro front end scheme
  • Summary of Qiankun Micro-front-end Practice (II)

If you have any questions or mistakes, please point them out!

🏆 technology project stage 4 | chat micro front end of those things…