Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to realize the web micro-front sandbox

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "how to achieve the web micro-front-end sandbox". The content of the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought. Let's study and learn "how to achieve the web micro-front-end sandbox"!

Background

The application sandbox is probably the most interesting part of the micro-front-end technology system. Generally speaking, sandbox is not necessary in the micro-front-end technology system, because if the specification is done well enough, it can avoid some variable conflicts between reading and writing and CSS style conflicts. But if you are in a large enough system, you can not only ensure the reliability of the application through specifications, but also need technical means to deal with some conflicts at runtime. This is also part of the reason why sandboxing has become a micro-front-end technology system.

First of all, throughout the various technical solutions, there is a major premise that determines how to do this sandbox: the final micro-application is a single-instance or multi-instance hosting application. This directly determines the complexity and technical solution of the sandbox.

Single instance: only one micro-application instance exists at a time. At this time, all browser resources in the browser are exclusive to this application. The solution is largely to clean up and restore the site when the application is switched. It is relatively lightweight and easy to implement.

Multi-instance: resources are not exclusive to the application, it is necessary to solve the situation of resource sharing, such as routing, style, global variable read and write, DOM. There may be many situations to consider and the implementation is more complex.

At first, our idea was:

From the business scenario: we may have a situation where when a user operates a product A while associated with another product B, the application B needs to be awakened to do the action. Although it can be avoided from the product dimension, such as cutting to B and then switching back to A, to some extent, we limit the interaction of products for technical reasons.

From a technical point of view: it is easy to solve the multi-instance scenario, and the single-instance solution brings some complexity to the coding to some extent, for example, the business code needs to switch the business context on its own.

Recently, qiankun 2 has also changed its thinking, from single-instance support to multi-instance support, which more or less shows that multi-instance is a scenario worth investing and technologically conquering.

Based on the above considerations, we began to explore the implementation of our Browser VM sandbox. To sum up, it can be shown in the following figure:

JavaScript sandbox implementation

Sandbox environment structure

To implement the sandbox, we need to isolate the native objects of the browser, but how to isolate and create a sandbox environment? there is a vm module in Node to achieve similar capabilities, but the browser is not, but we can use the ability of closures and variable scope to simulate a sandbox environment, such as the following code:

Function foo (window) {console.log (window.document);} foo ({document: {};})

For example, the output of this code must be {}, not the document of the native browser.

So ConsoleOS (micro-front-end solution for Ali cloud management system) implements a plug-in for Wepback, which adds a layer of wrap code to the sub-application code when building the application code, creates a closure, and changes the browser native objects that need to be isolated into the following function closures, so that we can input simulated window, document and other objects when the application is loaded.

/ / Packaging Code _ _ CONSOLE_OS_GLOBAL_HOOK__ (id, function (require, module, exports, {window, document, location, history}) {/ * Packaging Code * /}) function _ _ CONSOLE_OS_GLOBAL_HOOK__ (id, entry) {entry (require, module, exports, {window, document, location, history})}

Of course, it can be achieved without engineering, or by requesting a script, then splicing the code at run time, and then eval or new Function to achieve the same goal.

Native object simulation

With the sandbox isolation capability, the remaining problem is how to implement the native objects of this bunch of browsers. The initial idea was that we implemented according to the ECMA specification (there are still similar ideas), but found that the cost was too high. However, after our various experiments, we have found a very "tricky" approach. We can new iframe objects and extract native browser objects through contentWindow. Because these objects are naturally isolated, we save the cost of our own implementation.

Const iframe = document.createElement ('iframe')

Of course, there are many details to consider, such as: only the iframe of the same domain can extract the corresponding contentWindow. So you need to provide an empty co-domain URL of the host application as the URL for the initial load of this iframe. Of course, according to the specification of HTML, this URL uses about:blank to ensure that it is in the same domain and resource loading will not occur, but it will happen that the history associated with this iframe cannot be manipulated, and the route transformation can only be changed to hash mode.

As shown in the figure below, after we take out the native objects in the corresponding iframe, we will generate the corresponding Proxy for the specific objects that need to be isolated, and then make some specific settings for some property acquisition and property settings. For example, window.document needs to return a specific sandbox document instead of the current browser document.

Class Window {constructor (options, context, frame) {return new Proxy (frame.contentWindow, {set (target, name, value) {target [name] = value; return true;}, get (target, name) {switch (name) {case 'document': return context.document Default:} if (typeof target [name] = = 'function' & & / ^ [Amurz] / .test (name)) {return target [name]. Bind & & target [name] .bind (target);} else {return target [name];});}}

I won't go into details about the implementation of each object here. If you are interested, you can take a look at our open source code: https://github.com/aliyun/alibabacloud-console-os/tree/master/packages/browser-vm

But in order for the document to be loaded on the same DOM tree, for document, the properties and methods of most DOM operations are directly used by the properties and methods of the document in the host browser.

Because the sub-application has its own sandbox environment, all previously exclusive resources are now exclusive to the application (especially location, history), so the sub-application can be loaded at the same time. And for some variables, we can also set some access permissions in proxy to limit the ability of sub-applications, such as Cookie, LocalStoage read and write.

When the iframe is removed, the variable written in the window and some of the timeout times set are also removed (of course, the DOM event needs to be sandboxed and then removed in the host).

To sum up, our sandbox can do the following features:

CSS isolation

CSS isolation schemes are relatively general, and the common ones are:

CSS Module

Add namespace for CSS

Dynamic StyleSheet

Shadow DOM

CSS Module or CSS Namespace

By modifying the basic component style prefix, the framework and micro-applications rely on the isolation of the basic component style (depending on the preprocessor compilation and runtime basic component library configuration of the CSS on the project), while avoiding the writing of global styles (depending on conventions or engineering lint means).

Dynamic StyleSheet

The isolation method is to avoid style conflicts by dynamically loading and unloading micro-application stylesheets during JS runtime. One limitation is that there is still the possibility of style conflicts between the site framework itself or its components (header/menu/footer) and the currently running micro-applications, and the other is that there is no way to support multiple micro-applications running and displaying at the same time.

Shadow DOM

The advantage is the style isolation provided at the browser level, which can be completely isolated. The disadvantage is that the current compatibility is not very good, and the transformation will involve the transformation of the business code of the old application, and the invasion of the sub-application is relatively high.

In the end, after practice, the way we chose was CSS Module + to add CSS's namespace. CSS module ensures that the application business style does not conflict, and Namespace ensures that the common library does not conflict. We have implemented a postcss plug-in that prefixes all styles when building the application, including the CSS of the application common library (which makes it easy to make the new and old versions of the same component library compatible). As shown in the following figure:

/ / host host app. Next-btn {color: # eee;} / / Sub-application sub app aliyun-slb. Next-btn {color: # eee;} / / nodes generated in the host

The benefits of this implementation are:

Each application has namespace, which allows multiple instances to coexist.

Does not rely on a specific CSS preprocessor.

Complete isolation can be achieved for different versions of CSS in the same library, such as fusion1 and fusion2.

In view of the existence of the above JS sandbox, for some pop-up components, the body obtained by this micro-application is actually a host-generated node, so the pop-up window will be added to the micro-application node (that is, the aliyun-slb above), and the style will not be invalidated.

However, there will be some problems, such as:

The issue of nested application component style priority. Due to the existence of CSS module, it generally occurs only in public CSS styles, which can only be avoided as much as possible.

Problems with common fonts in different versions of fusion libraries. The current solution: compare hack and replace the name of the next font by engineering.

How to integrate with other systems

If you read the above article and think that this sandbox scheme is good, but you already have your own micro-front-end system, what if you want to apply it?

At present, the ConsoleOS code is open source on Github: http://github.com/aliyun/alibabacloud-console-os, you can try it here.

JS sandbox part

If you understand the above introduction to the principle, you can see that the sandbox implementation actually consists of two levels:

Simulation of native browser objects (Browser-VM)

How to build a closure environment

Browser-VM can be used directly, and this part is completely universal. But when it comes to this part of closure construction, each micro-front-end system is not consistent and may need to be modified, such as:

Import {createContext, removeContext} from'@ alicloud/console-os-browser-vm'; const context = await createContext (); const run = window.eval (`(() = > function ({window, history, locaiton, document}) {window.test = 1;}) ()`) run (context); console.log (context.window.test); console.log (window.test); / / manipulate the virtualization browser object context.history.pushState (null, null,'/ test') Context.locaiton.hash = 'foo' / / destroy a context await removeContext (context)

Of course, you can directly choose the sandbox to provide a good evalScripts method:

Import {evalScripts} from'@ alicloud/console-os-browser-vm'; const context = evalScripts ('window.test = 1') console.log (window.test = = undefined) / / true

CSS sandbox

If you build with Webpack, you can configure it directly as follows:

Const postcssWrap = require ('@ alicloud/console-toolkit-plugin-os/lib/postcssWrap') / / the following is webpack config {test: /\ .css $/, use: ['style-loader', {loader:' postcss-loader', options: {plugins: [/ / add plug-in postcssWrap ({stackableRoot: '.prefix') Repeat: 1})],},}, 'css-loader',], exclude: / ^ node_modules$/,} Thank you for your reading The above is the content of "how to achieve web micro-front-end sandbox". After the study of this article, I believe you have a deeper understanding of how to achieve web micro-front-end sandbox, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report