preface
MicroApp is a micro front end framework based on WebComponent-like rendering. Different from popular open source frameworks, it implements micro front end from component-based thinking, aiming to reduce the difficulty of getting started and improve work efficiency. It is the lowest cost framework for micro front end in the market at present, and provides JS sandbox, style isolation, element isolation, preloading, resource address completion, plug-in system, data communication and a series of perfect functions. MicroApp is stack independent and not business bound, and can be used with any front-end framework and business.
In this article, we will introduce MicroApp from the business background, implementation ideas, and its use and technical principles in detail.
Business background
With the rapid development of the Internet over the years, many enterprise web application in the last iteration function is more and more complex, participate in the rising number of staff, team, lead to the problem of difficult to maintain project, this is especially common PC, many research and development team is also looking for a highly efficient management of complex application scheme, so the micro front-end mentioned more frequently.
The micro front end is not a new technology, but rather an architectural idea that takes a single Web application and breaks it down into smaller applications that can be developed, run, and deployed independently, and integrates them into a single application.
In real business, we also encountered the same problem, and tried various solutions in different business scenarios, such as iframe, NPM package, micro front-end framework, and compared the advantages and disadvantages of each solution.
Iframe: Of all the micro front-end solutions, iframe is the most stable and least difficult to get started, but it has some problems, such as low performance, complex communication, double scroll bars, pop-ups, no global coverage, it is not high growth, only suitable for simple page rendering.
NPM package: Encapsulating sub-applications into NPM packages and introducing them as components is the optimal solution in terms of performance and compatibility. However, a fatal problem is version update. Each release of the version needs to notify the access party to synchronize the update, which makes management very difficult.
Micro-front-end frameworks: Popular micro-front-end frameworks include single-SPA and Qiankun, which strike a balance between maintenance cost and functionality and are currently the most popular solutions for micro-front-end implementation.
Due to problems with Iframe and NPM packages that cannot be solved theoretically, Initially We adopted Qiankun as the solution. Qiankun is packaged on the basis of single-SPA, providing js sandbox, style isolation, preloading and other functions. Besides, it is independent of technology stack and can be compatible with different frameworks.
Business demands
Qiankun was excellent, but it still didn’t meet our expectations. The first question is, in our actual usage scenarios each detail front projects have run a long time, and each project shall be the responsibility of the different staff and team, how to reduce the source of invasive, less code changes and communication costs, this is a matter of great concern to us, so we need a smaller than the cost qiankun access scheme. The second problem is that in the case of multi-party application access, the sandbox is not a perfect way to avoid all problems, but Qiankun’s ability to deal with such unexpected problems is not very efficient. In the process, we found an extremely concise implementation that is as simple as using components, can be connected to a micro front end with a few code changes, and provides a plug-in system that gives developers the flexibility to deal with problems.
Implementation approach
The micro front end is divided into main application and sub-application. The main application, also known as base application, is the container carrier for other applications, and the sub-application is the embedded side. From the perspective of main application and sub-application, we explore a more concise and effective way to connect to the micro front end.
Reflections on Qinkun and single-SPA
In single-Spa and Qiankun, we listen for the URL change event, which matches the subapplication to render when the route changes. This kind of routing listening rendering is the earliest implementation of single-SPA. As the earliest and most influential micro front-end framework, single-SPA has been used for reference by many frameworks and companies. As a result, most of the micro front-end methods currently implemented are based on routing listening.
At the same time, single-SPA requires the subapplication to modify the rendering logic and exposes three methods: bootstrap, mount, and unmount, which correspond to initialization, render, and unmount respectively, which also causes the subapplication to modify the entry file. This feature has also been inherited by Qiankun and requires some modifications to the WebPack configuration.
Are routing based listening implementations and modifications to subapplication entry files and Webpack configurations required?
Is not, the front end is at the heart of resource loading and rendering, rendering is a typical iframe, so long as can realize the function of an element segregation and routing requirements, son application theory does not need to modify the code can be embedded into another page rendering, we try to find the different implementation from this Angle.
Componentization of micro front end
In order to simplify the implementation steps of the micro front end, we must abandon the old implementation idea and explore a different path.
We draw lessons from the idea of WebComponent, based on which we introduce another more component-based implementation: class WebComponent + HTML Entry.
HTML Entry: Set HTML as the resource Entry, load remote HTML, parse its DOM structure to obtain JS, CSS and other static resources to achieve micro front-end rendering, this is also the current rendering scheme used in Qiankun.
WebComponent: Web native component, which has two core components: CustomElement and ShadowDom. CustomElement is used to create custom tags, ShadowDom is used to create ShadowDom, which has natural style isolation and element isolation attributes. Since WebComponent is a native component, it can be used in any framework and is ideally the best solution for implementing a micro front end. However, WebComponent has a problem that can’t be solved – ShadowDom compatibility is very poor, and some front-end frameworks don’t work in ShadowDom environments, especially the React framework.
WebComponent class: it is to use the CustomElement combined with the custom ShadowDom to achieve the basic consistent function of WebComponent.
Due to the problems existing in ShadowDom, we adopted custom style isolation and element isolation to achieve similar functions of ShadowDom, and then encapsulated the micro front-end application in a CustomElement, thus simulating and implementing a WebComponent-like component. Its usage and compatibility are consistent with WebComponent, while avoiding ShadowDom issues. And because of the isolation feature of custom ShadowDom, Micro App does not require subapps to modify rendering logic and expose methods like single-Spa and Qiankun, nor does it need to modify WebPack configuration.
The above solution encapsulates a custom tag micro-app that has a rendering mechanism and functionality similar to that of a WebComponent, allowing developers to access the micro front end as if it were a Web component. It is compatible with any framework and is more componentized in terms of usage and data communication, which significantly reduces the access cost of a base application, and because of the element isolation attribute, the change rate of sub-applications is also greatly reduced.
use
Next, we will introduce the access mode of the main application and the sub-application respectively.
Take the React code for example
The main application
Each custom tag micro-app is rendered as a micro front-end subapp, which is used in a similar way to iframe tags.
We need to pass three basic attributes to the tag:
- Name: name of the
- Url: indicates the address of the child application page
- Baseurl: Baseurl is the route prefix that the base application assigns to its children
The usage is as follows:
The child application
If the child application has only one page and no routing configuration, no changes need to be made.
If the sub-application has multiple pages, you only need to modify route configurations and add route prefixes.
As follows:
Window. __MICRO_APP_BASE_URL__ is the route prefix delivered by the base application. In non-microfront-end environments, this value is undefined
Complete the above configuration can achieve micro front-end rendering, the source of the change momentum is very few. Of course, MicroApp provides other capabilities, such as plug-in systems and data communication, which we will discuss in detail next.
Core principles
The core function of MicroApp is built on the basis of CustomElement, which is used to create custom tags and provides hook functions such as element rendering, unloading, attribute modification and so on. We know the rendering time of MicroApp through hook functions, and take custom tags as containers. None of the elements and style scopes of a microapplication can escape the container boundary, resulting in a closed environment.
Concept map
Rendering process
Through the connectedCallback function of the user-defined element micro-app life cycle, listen to the element being rendered, load the HTML of the child application and convert it to THE DOM structure, recursively query all static resources such as JS and CSS and load them, set element isolation, and intercept all dynamically created script, link and other tags. Extract the tag content. After the loaded JS is processed by the plug-in system, it is put into the sandbox to run, and the STYLE isolation of CSS resources is carried out. Finally, the formatted elements are put into micro-app, and the micro-APP element is finally rendered as a micro-front-end sub-application. During rendering, the developer bound lifecycle functions are executed for further operations.
The flow chart
Elements in isolation
Element isolation comes from the concept of ShadowDom, that is, elements in ShadowDom can be repeated with external elements without conflict, and ShadowDom can only operate on its own internal elements.
MicroApp emulation implements a similar function. We intercept the methods of elements on the underlying prototype chain, ensuring that sub-applications can only operate on their own internal elements, and that each sub-application has its own element scope.
Element isolation can effectively prevent the child application from misoperating the base application and other child application elements. A common scenario is that the root elements of multiple applications all use the same ID. Element isolation can ensure that the rendering framework of the child application can correctly find its own root element.
Concept map
The actual effect
As shown in the figure above, the micro-app element internally renders a child application. It also has two custom elements, micro-app-head and micro-app-body, which correspond to the HEAD and body elements in HTML, respectively. The content of the child application in the original head element and some dynamically created and inserted head link and script elements will be moved to micro-app-head, and the content in the original body element and some dynamically created and inserted body elements will be moved to micro-app-body. In this way, the elements of child applications can be prevented from leaking to the whole world. When the operation such as element query and deletion is carried out, it only needs to be processed inside the micro-app, which is an important basis for realizing element isolation.
Micro-app can be understood as an embedded HTML page, similar in structure and function to AN HTML page.
Plug-in system
The use scenarios for the micro front end are so complex that even a sandbox mechanism can’t avoid all the problems, so we provide a plug-in system to solve some unpredictable problems.
A plug-in can be understood as an object that conforms to certain rules and provides a function to handle a resource. A plug-in is usually defined by the developer.
The function of the plug-in system is to conduct preliminary processing on the incoming static resources, and call the qualified plug-ins in turn. The static resources after preliminary processing are passed into the plug-in as parameters, and the plug-in further modifs the content of the resources and returns the modified content. The plug-in system gives developers the flexibility to deal with static resources and modify problematic resource files.
The plug-in system itself is pure and has no impact on the content of the resource. Its function is to orchestrate how the plug-ins are executed, so that when the developer does not set up the plug-ins, the content coming in and going out is consistent.
Js sandbox and style isolation
Js sandbox uses Proxy to Proxy global objects of child applications to prevent conflicts of global variables between applications, record or clear global side functions of child applications, or inject global variables into child applications for customization.
Style isolation formats the CSS content of the link and Style elements of the child application to ensure that the style of the child application only has its own scope and does not affect the external environment.
MicroApp borrowed from Qiankun’s JS sandbox and style isolation scheme, which is also widely used and mature.
preload
MicroApp provides the ability to preload child applications. It is based on requestIdleCallback. Preloading has no impact on the rendering speed of the dock application and other child applications.
Resource address completion
The reason is that the base application loads the resources of the child application into its own page rendering. If the static resource address of the child application is a relative address, the browser will complete the static resource with the domain address of the base application, resulting in the loss of resources.
Resource address completion is to complete the relative address of the static resource of the child application into the absolute address to ensure that the address points to the correct resource path. This operation is similar to webPack setting publicPath at runtime.
The life cycle
In microapplication rendering,micro-app
The base application can listen for events that trigger lifecycle events at different rendering stages.
Life Cycle list:
- Created: Executed after the micro-app tag is created but before the resource is loaded.
- Beforemount: The resource is loaded and executed before rendering.
- Mounted: The child application is rendered and executed
- Unmount: Executed when the child application is unmounted.
- Error: Executed when a destructive error occurs and rendering cannot continue.
During uninstallation, the child application also receives an uninstallation event to perform uninstallation related operations.
Data communication
Data communication is a very important function in micro front end. There are many technical solutions to realize data communication. Excellent solutions can improve the development efficiency and reduce the cost of trial and error. We also studied the way of data communication of micro-front-end frameworks like Qiankun, but their implementation method is not suitable for us. We try to achieve data communication in the form of transferring complex data directly through element attributes.
The most familiar way for front-end developers is the componentized data interaction. As a WebComponent, the custom element Micro-App is bound to be the optimal way for data interaction through component attributes. But the biggest problem MicroApp has with data communication is that custom elements do not support setting object type attributes, such as
To solve this problem, we rewrite the method of setting the properties on the prototype chain of the micro-App element. When setting the object properties of the Micro-App element, we save the passed values to the data center and distribute the values to the child applications through the data center.
Data in MicroApp is bound to communication, that is, each micro-app element can only communicate with the sub-applications it points to, so that each application has a clear data link to avoid data chaos. Meanwhile, MicroApp also supports global communication to transfer data across applications.
Data communication concept map
Framework of contrast
In order to feel the difference between Micro App and other frameworks more intuitively, we use a graph for comparison.As can be seen from the comparison diagram, all the functions in the current open source micro front-end framework MicroApp has, and provides some functions that they do not have, such as static resource address completion, element isolation, plug-in system, etc.
Business practices
MicroApp has been used in many projects within the company and has performed well. In particular, some old projects have been transformed into micro fronts, which can reduce the access cost and ensure the smooth operation of the project and reduce the coupling without affecting the project.
Why open source?
When our team originally planned to use the micro front end, we investigated the market framework to implement the micro front end, and only Sigle-SPA and Qiankun were available. Single-spa is too basic, with too many modifications to the original project and too high cost. The rest of the only Qiankun, but because of access to a lot of old projects, in the actual use of a lot of problems, we have to qiankun source code for a lot of magic change. Along the way, we developed some ideas about how a micro front end could be implemented and put those ideas into practice, resulting in MicroApp.
Currently, there are too few micro-front-end frameworks like The one in Qiankun that provide perfect functions. When the access to Qiankun fails, there is no other solution to choose from. This is the pain we experienced in the beginning. Therefore, we choose to open source MicroApp. Firstly, MicroApp has many innovative points, which can be more easily connected to the micro front end with richer functions. Secondly, it can give people one more choice.
If you are interested in the project, you can join the organization or pull requests, and you are welcome to join.
navigation
GitHub: github.com/micro-zoe/m…
Website address: cangdu.org/micro-app
Special thanks: Qiankun