What is a micro front end

Let me give a more precise definition of a micro front end. A micro front end is an aggregation of several small front end applications that are separate from each other but run in aggregation.

One of the core things is decoupling, decoupling at the project level.

In the current front-end field, single-page application (SPA) is one of the most popular project forms. As time goes by and the application functions become more and more rich, this stupid thing will become more and more complex, and will become a so-called monolith system, with high development cost and high mental loss for engineers. For example xiao ge told me that we this CMS on some places dare not change, change do not know which is broken, pull a launch the whole body. Or, for example, if the CMS develops two requirements at the same time under the same schedule, then both development and testing will be troublesome. And the earlier the micro front end starts, the better, when it really becomes a monolith system is hard to break down.

One function brought on this basis is the replacement of technology stack. For example, CMS uses VUE 2.x and now wants to use the newly released VUE 3. If large-scale reconstruction is carried out, the cost is very high. After all, we are decoupled from each other at the project level, so you can use them however you like.

The point of the micro front end is to break these massive applications apart and then decouple them so that each part can be maintained and deployed separately to improve efficiency.

Microfront-end solution

Probably the following

plan describe advantages disadvantages
MPA + Route forwarding Nginx configates location to realize the mapping of different paths to different applications, such as www.abc.com/app1 corresponding to APP1 and www.abc.com/app2 corresponding to APP2. This scheme itself is not the transformation of the front-end level, but the configuration of operation and maintenance. Simple, fast and easy to configure Jumping between applications triggers the browserThe refresh, the impactexperience

Jump between applicationsLoading timeA long

Does not supportMultiple applications on the same screen
Nested iframe The parent application is a single page, and each child application has an iframe nested. The parent and child can communicate in postMessage or contentWindow mode Simple implementation, the sub application between their own sandbox, natural isolation, mutual influence Intercomponent communication.cookieThe limits of

uiOut of sync, for exampledialogUnable to fill the full screen

Forward and backward keysCan’t use
Web Components Each sub-application needs to use pure Web Components technology to write Components, which is a new set of development mode Each sub-application has its own script and CSS and can be deployed separately High cost for historical system transformation

Subapplication communicationMore complex and easy to step pit
Combined application route distribution Each child application is built and deployed independently. At runtime, the parent application performs routing management, application loading, startup, uninstallation, and communication mechanisms Pure front-end transformation, good experience, no perception switch, sub-applications isolated from each other Intrusive development

Need to solve the sub-applicationstyleConflict,The variable objectPollution,Communication mechanismSuch as technical point

There is no level of technical solutions, only pros and cons.

Finally, we decided to use this combined application routing distribution, which I like to call pedestal micro front end for short, probably because it is more balanced, better experience, more controllable, and more solutions.

Process for the master application to load child applications

For example, enter log.feihua100.com/course-mana…

  1. Main application loading (web request, JS execution, page rendering)

2. Main application basisroutingGet the child application name:course-manage

{
    name: 'course-manage',}Copy the code
  1. Obtained by the main applicationcourse-manageThe configuration of the
{
    name: 'course-manage'.entry: process.env.NODE_ENV === 'development' ? '//localhost:7799/' : '/course-manage/'.activeRule: '/course-manage'.// The div mounted by the child application
    container: '#subapp-viewport'.props: {
        routerBase: '/course-manage',
        store
    }
}
Copy the code
  1. The primary application loads the child applicationcourse-manageStatic resources (HTML, CSS, JS)

  1. Child application receiverrouting. The route in the address bar matches the corresponding routevueFile, start renderingcourse-manageThe application incontainer(byidTo find thediv)

Micro front end implementation principle

The essence of micro-front-end is to deal with front-end applications and the relationship between applications. Then, to further implement a micro-front-end framework, three core elements will be involved:

  • Sub-application loading;

  • Runtime isolation between applications;

  • Communication between applications;

We will explain the above three points by explaining the API and source code of Qiankun, ant Financial open source stable micro front-end framework

Qiankun can be considered as the product of the secondary development by the combination of single-SPA and import-HTmL-Entry libraries

RegisterMicroApps method

The first is the registerMicroApps method, one of the core apis of Qiankun

This function registers the child application and, when the child application is activated, creates a run sandbox that calls different lifecycle hook functions at different stages.

It receives an array, which is the configuration of the child application.

In fact, what registerMicroApps basically does is deduplicate the array, iterate through the array and pass the configuration of each child application to registerApplication, the core function that registers the child application in single-SPA. As we mentioned, part of the core of Qiankun is single-SPA.

The input parameters to registerApplication are

  • Name – Name of the sub-application

  • ActiveRule – Activation rules for child applications

  • Callback-activerule callback when activated

  • Props – Data that the main application needs to pass to the child application

The registerMicroApps method is well understood as a way to register child applications with the master application, followed by another core method

The start method

The start function initializes some global Settings and then starts the application

The source code shows that Qiankun supports some prefetch preloading.

Then we can see that the global configuration is stored in the frameworkConfiguration, and a polyfill operation is performed. Let’s look at the details of this method:

From this we can see that the sandbox content is done by window.Proxy, if not by snapshot.

Finally, the start application is actually using the single-SPA start method.

LoadApp method

In the registration and initialization process above, we know that a callback will be executed when the current URL matches activeRule

The core is the return of the loadApp method, so this is the core method of the runtime, how do we load the child when we match the child, so let’s look at the loadApp method, okay

It’s too long to watch

This is the definition and configuration of some variables. Line 266 calls importEntry, which is the core method of the import-html-entry library

ImportEntry and importHTML methods

Let’s look at the importEntry method first

We can see that the core importHtml method is called directly when entry is a string, and then a chunk of it is returned when entry is configured, which can be approximated as an extension of the importHtml method. So it’s almost like the importHtml method is called. Let’s look at the importHtml method.

The fetch method, the publicPath method, and the template method can all be customized

  1. We see that our entry is requested directly using fetch, is that why Qiankun needs sub-applications across domains

  2. And then it returns an HTML template to string it

  3. The default getPublicPath is the upper-level route to get the entry. If the static resource address is not the upper-level route to get the entry, you need to customize the getPublicPath method

  4. Then there is the processTpl method, which parses all the JS scripts from a messy HTML template — including the outgoing address and the inline code block. The addresses of all link tags are the style addresses. There is no inlining, because the styles are converted to the inline style.

– template: indicates the script that has been processed. The link and script tags are commented out

HTTP address | – scripts: [script code block],

-styles: [HTTP address for styles]

– Entry: Indicates the address of the entry script, either the SRC of the script marked with entry or the SRC of the last script tag

This method is actually very interesting, can learn some link and script writing, but too tedious to talk about.

  1. To process an HTML template using the getEmbedHTML method is to use fetch to remotely load all external styles, then replace the corresponding external styles with inline styles, and finally return the processed HTML template.

  2. The final return is an object with the following attributes:

– template: indicates the processed HTML template

– assetPublicPath: indicates the static resource address

– getExternalScripts: Method of getting the previously parsed script array

-getexternalStylesheets: Method to get the array of stylesheets parsed earlier

– execScripts: execute all JS script files in this template file and specify the scope of the script. – proxy object

The section above can be considered as sub-application loading. This section explains the principle of sub-application resource loading, followed by the section of runtime isolation between applications.

Back to the loadApp method

Then there is the singleton pattern, where the new child application mount behavior starts after the old child application is unmounted.

Then a section of sandbox mode configuration, will talk about the implementation principle.

Next, the HTML of the sub-application was processed by templates and other methods and mounted in the container configured in the main application. It can also be seen here that qiankun was equipped with a loading mechanism of the sub-application.

The sandbox mechanism

The application of this part we have in front of the child after HTML processing in the application of our Lord in the container, and we know that much of the front page on the operation of the main body is the js, and js run most based on our window object, but when we are the main application and the application of parallel, or even more child applications in parallel, Our Window objects are likely to be contaminated with each other.

The qiankun project used a sub-application state management solution, js sandbox, in ProxySandbox, LegacySandbox and SnapshotSandbox.

SnapshotSandbox

The first is to use the SnapshotSandbox sandbox as a class when the window.Proxy property is not supported in earlier versions of browsers

attribute meaning
name The name of the sandbox
proxy The proxy object, here iswindowobject
sandboxRunning Whether the current sandbox is running
windowSnapshot Window Status Snapshot
modifyPropsMap The sandbox was modified during operationwindowattribute
active Activate the sandbox and start it when the child application is mounted
inactive Close the sandbox and start it when the child application is uninstalled
constructor Constructor to create a sandbox environment

There are two main methods of SnapshotSandbox, which are the implementation of its core functions.

The first is to activate the active method of the sandbox, which takes a snapshot of the window and restores the state of the sandbox if it has previously stored state:

The other is to disable the sandbox method inactive, which takes a snapshot of the Window object and records the state change of the sandbox:

The SnapshotSandbox sandbox uses snapshots to isolate the state of window objects. In contrast to ProxySandbox, the SnapshotSandbox will pollute the Window object during child application activation, which is a backward compatibility scheme for browsers that do not support the Proxy property.

LegacySandbox

Then there is the LegacySandbox sandbox, which as a class lets examine its properties

attribute meaning
addedPropsMapInSandbox Global variables added during sandbox forClose the sandboxTo restore the global state
modifiedPropsOriginalValueMapInSandbox Global variable updated during sandbox, used forClose the sandboxTo restore the global state
currentUpdatedPropsValueMap Keeps a map of updated (new and modified) global variables used inActivate the sandboxTo restore the independent state of the sandbox
name The name of the sandbox
proxy Proxy object, which can be understood as a child applicationglobal/windowobject
sandboxRunning Whether the current sandbox is running
active Activate the sandbox and start it when the child application is mounted
inactive Close the sandbox and start it when the child application is uninstalled
constructor Constructor to create a sandbox environment

In fact, since LegacySandbox serves the singleton pattern, its core implementation is largely similar to that of SnapshotSandbox. Let’s look at the Active and Inactive methods.

In fact, we can see that this is also in the form of a snapshot. The difference is that window.Proxy is used as a Proxy, so it can listen on get and set to change the record:

We can see from the source code, in fact, LegacySandbox mode is actually a direct operation of the Window object, but there is no pollution between the child applications, and between the parent applications will cause window pollution.

The proxy object is the parameter used by the execScripts method above, which specifies the context in which JS is executed.

Finally, take a look at multi-instance sandbox ProxySandbox

ProxySandbox

Again, let’s look at the attributes in the class:

attribute meaning
updatedValueSet Keep track of the updated values in the sandbox, which is a separate state pool for each child application
name The name of the sandbox
proxy Proxy object, which can be understood as a child applicationglobal/windowobject
sandboxRunning Whether the current sandbox is running
active Activate the sandbox and start it when the child application is mounted
inactive Close the sandbox and start it when the child application is uninstalled
constructor Constructor to create a sandbox environment

ProxySandbox does not operate directly on the Window object. Instead, ProxySandbox copies a fakeWindow object as a proxy:

There is no need to restore or reset Windows since they are not directly operated:

While updatedValueSet will synchronize the records of operations on fakeWindow:

So I have a question, since parent and child applications don’t pollute Windows with each other, does this update Valueset make any sense?

In summary, ProxySandbox is the most complete sandbox mode, completely isolating the state of the master application.

Above is the section about Windows in runtime isolation between applications. We know that we have some side effects that need to be isolated from each other, such as event listeners, timers, etc.

Listening to hijack

The main content is in patchAtMounting method

Here are three types of monitoring hijacking, respectively:

  • patchTimer

  • PatchWindowListener (Window event listener hijacking)

  • PatchHistoryListener (Route Listener)

patchTimer

The first is the patchTimer hijacking:

The idea here is relatively simple, is to do a layer of proxy timer, let’s find someone to explain the principle here?

The main thing is to create a state pool and maintain the ID so that it can be released uniformly when uninstalling child applications.

The principles of patchWindowListener and patchHistoryListener and patchTimer are not explained in detail

There are some other side effects of loading and unloading that I won’t go into.

Style isolation

Above are the contents of THE JS sandbox isolation, let’s talk about the CSS style isolation method.

Qiankun provides two types of CSS style isolation:

  • Shadow DOM

  • CSS Scoped

Let’s do it separately

Shadow DOM

The Shadow DOM allows you to attach a hidden DOM tree to a regular DOM tree — it starts with a Shadow root node, and underneath that root node can be any element, just like a normal DOM element. The hidden DOM style is completely isolated from the rest of the DOM, similar to the style isolation effect of iframe.

I won’t go into the details, it’s not interesting, and I’ll talk about why it’s not interesting

CSS Scoped

Next up is CSS Scoped, which I named Experimental Sandbox, adding suffix tags to all styles of sub-applications such as div[data-Qiankun-Microname].

At the same time, turn the CSS into a selector of this form, and you can make a CSS sandbox.

However, neither of these two methods can solve the problem of popovers. Popovers are mostly bound to the root node, which is to jump out of the sandbox, resulting in a problem with the style of popovers.

At this point we can manually tie the popover to the child application to solve this problem.

If we don’t use CSS sandboxes, can we use Webpack to solve the problem of style isolation?

Remote Patch request

All we’ve talked about above is the mount and unmount life cycle, but we actually have some style files or JS files that append to the page using remote requests, and there’s another layer of isolation.

The qiankun solution is exactly the same as some of these: Augmenting the appendChild and insertBefore methods and adding some additional logic to determine whether link, style, and script elements are inserted in the main or microapp depending on whether they are children, and hijacking the addition of script tags. Supports remote loading of scripts and setting the execution context of scripts, also known as Proxy. I’m not going to get into the code because it’s complicated.

That concludes the section on runtime isolation between applications.

Communication between applications

The last one is about inter-application communication, which can be completed through the API of Qiankun. It is the content of actual combat. You can see the scheme in the article of enterprise-class micro front-end combat.

conclusion

This sharing is quite long, and the general process is as follows

  • What is a micro front end

  • The advantages and disadvantages of micro – front-end schemes are compared

  • Describes the micro front end solution we use

  • This paper describes a process of main application loading sub-application in our scheme

  • Finally, through the analysis of the library of The Qiankun UMI group, the principle is simply described in the source layer

I hope this sharing can be of some help to your work.