This article is mainly my work record, no teaching or popular science purpose, interested teachers and students can see ~. ◕ ‿ ◕. ~!!!

1. Project Background

At present, the FE team is mainly responsible for the management system of the B-terminal. Over time and with the integration of more independent functions (involving older application integrations), coupled with frequent staff and team changes, it is inevitable that systems will become larger and harder to maintain. At the same time, at the current pace of innovation in front end technology, it is unlikely to ensure that a technology solution is sustainable for the long term, so how to ensure smooth migration of legacy code and new technology access in a few years will also be a problem. Therefore, it is very important to choose the early technical system and design the system software architecture, so as to avoid the system becoming a boulder application prematurely. We mainly consider the following aspects:

  1. How to deconstruct the Boulder app so that team members own a separate feature?
  2. How to solve maintenance problems caused by frequent staff and team changes?
  3. How to solve the technology stack problem caused by technological innovation?

2, research

2.1 overview,

Microfront-end originates from the technical paradigm of microservice, the core of microservice is the abstraction or division of service, which is used to solve the problems of high concurrency and high availability on the server side. The micro front end is not the same as the micro service. The micro front end is a technical means and method for multiple teams to jointly build modern Web applications through independent publishing. The micro front-end architecture aims to solve the problem of non-maintenance of single application in a relatively long time span, when it evolves from a common application to a monolite application due to the increase and change of people and teams involved.

2.2, advantage

  • Technology stack independent main framework does not limit access to the application stack, microapplications have full autonomy.

  • Independent development, independent deployment of micro application warehouse independent, the front and back end can be independently developed, after the deployment of the main framework automatically complete synchronization update.

  • The incremental upgrade

    In the face of a variety of complex scenarios, it is usually difficult to upgrade or reconstruct the existing system completely, and the micro front end is a very good method and strategy to implement the gradual reconstruction.

  • Independent run time States are isolated between each microapplication and run time states are not shared.

2.2 Mainstream implementation scheme

  • Container mode, based on iframe;
  • Routing distribution, based on browser URL or framework routing module, with server agent for application distribution, such as Qiankun;
  • Microcomponent, an application packaged into independent modules, can be directly embedded to run;
  • EMP, built based on Webpack5 Module Federation, solves the problem of business separation rather than cross-framework invocation;
  • Containerization, combined with Web Components construction;

2.3 why Choose Qiankun

Most of the service systems are B-end PC background systems, and each subsystem is relatively independent, avoiding complex application nesting. Routing based distribution can fully meet service requirements. Qiankun has provided more than 200 online applications in Ant, and the company also has related practices.

3. System design

3.1. Functional architecture Diagram

3.2. Business Flow chart

3.3. Routing rules

The primary and sub-applications use hash mode, and the urls are as follows:

https://xx.xxxxxxxx.xxx/static/fe-xxx-qiankun/#/micro-app-xxx/xxxx/xxxx
Copy the code

In the command, /micro-app-xxx matches the master application route and the Sub-application Active route, which are used to distinguish different sub-applications. The latter path matches the router route inside the sub-application.

3.4. System construction

  • A common technology stack for different systems (VUE3 family buckets, Vite builds, Element Plus component libraries, typescript);

    Note: In theory, the technology stack can be diversified for different systems, and the Qiankun model does not rely on a unified technology stack.

  • At present, manual replication is based on fe-XXXX-XXX project, and scaffolding will be used in the later stage.

3.5 deployment scheme

Applications are deployed independently and do not affect each other.

4, problem,

4.1. Compile and package

Qinakun officially supports webpack, which does not provide vite compatibility. Mainly because Vite was packaged with ES Modules, Qiankun had problems running.

With reference to the third party Vite-plugin-Qiankun, we provided the capabilities of the vite-plugin-Qiankun-Enhance plug-in:

  • Unified inter-application communication capability is provided on the basis of Qiankun.
  • By modifying the INTRODUCTION mode of JS files in HTML, the sub-application execution mode of Qiankun was compatible.
  • Provides a series of utility functions.
    • Use anti-shake to solve the vue-router hook function repeat execution;
    • Vue-router Adds a unified prefix.

4.2 sub-application style adjustment

Because the subsystem page is embedded in the main system, the subsystem page will be reduced, and vw is partly used in the subsystem code, so the style of VH will go wrong and needs to be adjusted and adapted.

4.3. Style isolation

4.3.1 Introduction to the isolation scheme

  1. Default;

    Sandboxes can ensure style isolation between single-instance scenario subapplications, but cannot ensure style isolation between the main application and subapplications, or in multi-instance scenarios.

  2. StrictStyleIsolation: true,

    Strict style isolation mode. In this mode, Qiankun will wrap a ShadowDOM node for each micro-application container to ensure that the style of micro-application will not affect the whole world. Strict style isolation based on ShadowDOM is not a solution that can be used mindlessly. In most cases, it is necessary to access the application to make some adaptation to run properly in ShadowDOM.

  3. ExperimentalStyleIsolation: true,

    The qiankun will rewrite the styles added by the sub-application by adding a special selector rule for all style rules to limit their scope of influence, similar to the following structure:

// Assume the application name is react16.app-main {
     font-size: 14px;
   }

   div[data-qiankun-react16] .app-main {
     font-size: 14px;
   }
Copy the code

Note: @keyframes, @font-face, @import, @page will not be supported (i.e Will not be overwritten).

4.3.2 Comparison of isolation schemes

shadow dom
  1. [Fixed] The iconffont font cannot be loaded in the child application.

    • Fix the problem of @font-face registration failure in shadow dom mode #1061
    • @font-face doesn’t work with Shadow DOM?
    • Icon Fonts in Shadow DOM

    Shadow DOM does not support @font-face. When iconFONT is introduced, styles can be introduced, but the font file does not exist, so corresponding ICONS cannot be displayed.

    Solution: Place font file in main application load/use generic font file.

  2. Component library dynamically created elements cannot use their own styles;

    Dialog box or prompt window is through the document. The body. The appendChild added, so the introduction of CSS in the shadow of dom is unable to function outside elements, such as common popup window components, Popover, Popconfirm, etc.

    Solution: the agent document. The body. The appendChild method, namely the add new elements added to the shadow of the dom container, rather than the outside of the body node

   function proxy(shadowDom) {
     if (!document.body.appendChild.isProxy) {
       document.body.appendChild = new Proxy(document.body.appendChild, {
         apply(target, thisArg, node) {
           if (node[0].classList.contains('el-overlay')) {
             target.apply(thisArg, node);
           } else {
             shadowDom.appendChild(node[0]); }},get: isProxy, }); }}Copy the code
  1. Event broker;

    Events declared on columns such as the React component are eventually bound to the Document DOM node, and event broker listeners rely on bubbling to know when to process events. Since Shadow DOM events do not bubble up to the top level, proxy listeners do not come into play.

    When rendering a standalone React application, you can check if elements are in the Shadow DOM. Then register the top-level listener on Shadow Root.

    • Events not registered inside shadow dom
  2. SVG does not work;

experimentalStyleIsolation
  1. All kinds of weird style problems;

    • [💤 applicationvarVariable lost](# child applicationvarVariable missing).
  2. Second to shadow with dom (document. The body. The appendChild);

  3. The other;

4.3.3 Selection of isolation method

Eventually choose experimentalStyleIsolation, for the following reasons (main reference qiankun @ kuitos author in this article issues# 1061 recommendations) :

  1. Shadow DOM’s problems don’t stop there@font-faceThis scenario, plus SVG doesn’t work, event proxies, etc.
  2. Shadow dom practice down can not out-of-the-box solutions, Suggestions to solve the style with experimentalStyleIsolation isolation current problems;
  3. Qiankun team on cable application use experimentalStyleIsolation running, also found no big problem;
  4. Shadow of the dom version no longer recommend follow-up, follow-up after being experimentalStyleIsolation mature, will replace the shadow of the dom implementation, at the same time provide compatible migration solution;

Author’s view on Shadow DOM

Shadowdom has been around for nearly 10 years, but the ecosystem is far from being productive. React/Vue/Angular adaptation of Shadowdom is not their first priority. At this stage, we will invest more in scoped Style solution. Thinking with experimentalStyleIsolation consistent

At present, Qiankun only provides a shadow DOM container. If the application needs to run normally in the Shadow DOM container, it needs to make some adaptation by itself (there is a statement in the document). If Qiankun expects shadow DOM to become a complete solution out of the box, it should not only solve the font-face problem (maybe 1/10 of all problems), but also provide solutions for more general issues such as framework (R/V/A), component libraries, and compatibility. This is basically impossible to do. If we can’t provide a relatively complete solution, we tend to leave it to the users themselves.

4.3.4 Problems caused by style isolation

The child applicationvarVariable is missing

After the main application Settings experimentalStyleIsolation: true style confusion. The value of var was incorrect after the CSS class of the sub-application was prefixed. If the child application dialog style error is as follows:

/** child application, dialog style error */
div[data-qiankun="micro-app-mis"] .el-dialog__header {
  padding-top:;padding-right:;padding-left:;padding-bottom: 10px;
}

/** child application, reset.less. Overrides the parent application's. El-dialog__header */
div[data-qiankun="micro-app-mis"] * {
  margin: 0px;
  padding: 0px;
  box-sizing: border-box;
}

/** Parent application, dialog style */
.el-dialog__header {
  padding: var(--el-dialog-padding-primary);
  padding-bottom: 10px;
}

/** Parent application, reset.less. * /
* {
  margin: 0px;
  padding: 0px;
  box-sizing: border-box;
}
Copy the code

Error: var(– el-dialog-padding-primary) {error: var(– el-dialog-padding-primary) {error: var(– el-dialog-padding-primary);

.el-dialog {
  --el-dialog-padding-primary: 20px;
}
Copy the code
Repetition demo
  • 💤 Notes/Jobs/zyb/other/chrome – bug – rules. HTML
Think about the direction
  • Disable = true when swapNode is created in the CSS Class.

  • Add CSS to swapNode using appendChildren cause (×);

    const textNode = document.createTextNode(cssStr || ' ');
    swapNode.appendChild(textNode);
Copy the code
  • The Css structure.el-dialog__headerNot before.el-dialogCause (×);
    .el-dialog {
      --el-dialog-padding-primary: 20px;
      width: 100px;
      height: 100px;
    }

    .el-dialog__header {
      padding: var(--el-dialog-padding-primary);
      padding-bottom: 10px;
      width: 100%;
      height: 100%;
      background-color: red;
      box-sizing: border-box;
    }
Copy the code
  • When adding CSS to swapNode, there is no corresponding Html structure (×);
conclusion
  • bugs.chromium

Chrome’s bug. The ** CSS variable’s short property (e.g. padding: var(–a)) and the property’s specific property (e.g. padding-bottom: CssRules [index]. CssText (style-sheet. CssRules [index]. padding-right: ; padding-left: ; Padding – bottom: 10 px;) .

/ / errorpadding: var(--a);
padding-bottom: 10px;

// 1Right.padding: var(--a);

// 2Right.padding-top: var(--a);
padding-bottom: var(--a);
padding-left: var(--a);
padding-right: var(--a);
padding-bottom: 10px;
Copy the code
To solve
  1. Ostrich strategy, case by case;

  2. Convert CSS variables to concrete values;

    • 💤 Notes/laboratory/CSS – vars2value
  3. Change the time of adding the class prefix;

    Develop or use the existing vite/ Webpack tool chain to complete the class prefix operation of CSS in the sub-application construction phase. The Qiankun is a prefix operation that is done when a child application is being loaded, which takes up client performance.

The child application class prefix is missing
  • [💤4.2, asynchronous CSS prefix](#4.2, asynchronous CSS prefix)

ExperimentalStyleIsolation: true options there is not completely covered the inside of the application style, child application part of the CSS class added prefix, not appear in the following two cases.

  • CSS styles in vUE components are introduced in the development environment through JS;

    The ships environment and the formal environment are fine, because CSS styles are introduced through CSS files;

  • Introduce CSS by dynamically creating styles;

Lack of reason

Vite provides the updateStyle function in the development environment to update the class. The following two methods are called:

  • document.createElement('style');
  • document.head.appendChild;

The updateStyle function looks like this:

export function updateStyle(id: string, content: string) :void {
  let style = sheetsMap.get(id)
  if(supportsConstructedSheet && ! content.includes('@import')) {
    if(style && ! (styleinstanceof CSSStyleSheet)) {
      removeStyle(id)
      style = undefined
    }

    if(! style) { style =new CSSStyleSheet()
      style.replaceSync(content)
      // @ts-ignore
      document.adoptedStyleSheets = [...document.adoptedStyleSheets, style]
    } else {
      style.replaceSync(content)
    }
  } else {
    if(style && ! (styleinstanceof HTMLStyleElement)) {
      removeStyle(id)
      style = undefined
    }

    if(! style) { style =document.createElement('style')
      style.setAttribute('type'.'text/css')
      style.innerHTML = content
      document.head.appendChild(style)
    } else {
      style.innerHTML = content
    }
  }
  sheetsMap.set(id, style)
}
Copy the code

The two methods mentioned above were rewritten by Qiankun.

Qiankun rewrite the document. The head. The appendChild method (patchHTMLDynamicAppendPrototypeFunctions), Internally call the CSS. Process function of the Qiankun when the method is called to prefix the CSS.

Qiankun rewrite the document. The createELement method method (patchDocumentCreateElement) and added a wekmap will create results, The call to the document. The head. The appendChild function will check whether “style tags” and “whether the current style element by rewriting the document. The createELement method to create”.

Document. The head. The appendChild part code is as follows:

 getOverwrittenAppendChildOrInsertBefore(opts: {}) {
     // This is the reason why the CSS style does not add the class prefix
     if(! isHijackingTag(element.tagName) || ! isInvokedByMicroApp(element)) {// ...
       return. } css.process()Copy the code

Document. The prototype. The createElement method part code is as follows:

// is it style
if (isHijackingTag(tagName)) {

  // Is there a running sandbox?
  const {
    window: currentRunningSandboxProxy
  } = getCurrentRunningApp() || {};

  // This is the reason why the CSS style does not add the class prefix
  if (currentRunningSandboxProxy) {
    const proxyContainerConfig = proxyAttachContainerConfigMap.get(currentRunningSandboxProxy);
    if(proxyContainerConfig) { elementAttachContainerConfigMap.set(element, proxyContainerConfig); }}}Copy the code

The main reason for not getting runningApp is the following code

  private registerRunningApp(name: string, proxy: Window) {
    if (this.sandboxRunning) {
      setCurrentRunningApp({
        name,
        window: proxy
      });
      // FIXME if you have any other good ideas
      // remove the mark in next tick, thus we can identify whether it in micro app or not
      // this approach is just a workaround, it could not cover all complex cases, such as the micro app runs in the same task context with master in some case
      // Delete CurrentRunningApp in the next event loop to distinguish between the current code being executed in microApp and macroApp
      // Set CurrentRunningApp (in proxysandbox.ts)
      nextTask(() = > {
        setCurrentRunningApp(null); }); }}Copy the code

The following code will trigger the Proxy. The reason why the CSS style of some vUE components or pages of the child application can be correctly added with the class prefix, The setCurrentRunningApp was set because a call to the COMPONENT or page in qiankunWindow.__powered_by_QIANkun__ caused the Proxy get interceptor to be executed.

const proxyWindow = new Proxy(window, {
  get(target, p) {
    console.log('get');
    return Reflect.get(target, p); }})Copy the code

4.3.5 Popover style is invalid

Dialog box or hint window through the document. The body. The appendChild added to bodyu elements, as a result of the CSS style in the case of setting experimentalStyleIsolation will add class prefix, lead to the style of the dialog box or hint window components such as lost.

  1. Extract common style files to the main application;

  2. Rewrite the styles of all child applications;

    Add a class prefix starting with the name of the child application, such as.fe-xxx-xxx, and add the corresponding class name to the body when switching the child application in the main application.

4.4, cross-domain

HTML/CSS/js cross-domain

The primary application obtains the HTML, CSS, and JS resources of the sub-application, and these resources are served by the development server of the sub-application. This is resolved by default configuration of the child application development server.

XHR request for the child application

Requests from the child application sent by the master application are brokered by the development server of the child application to the test environment.

For example, the main application (http://test.suanshubang.cc:9000) to send application request (http://test.suanshubang.cc:3000), the development of child application server to request the agent to the ships to the environment. Error as follows:

Access to XMLHttpRequest at 'http://test.suanshubang.cc:3000/registrar/shop/info'
from origin 'http://test.suanshubang.cc:9000'
has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request'
s credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Copy the code

Add the following configuration to solve the problem.

cors: {
  origin: [/test\.suanshubang\.cc:\d+/].credentials: true,},Copy the code

Mock request for the child application

Requests from the master application to the child application are intercepted by the middleware provided by MockJS to the child application development server and the mock data is returned.

Such as: Main application (http://test.suanshubang.cc:9000) to send child application request (http://test.suanshubang.cc:3100), the child application internal use vite plugin – mock plug-in processing request returns. Error as follows:

Access to XMLHttpRequest at 'http://test.suanshubang.cc:3100/api/financial/calendar? startDate=2021-11-03&endDate=2021-11-09&rightRange[]=1'
from origin 'http://test.suanshubang.cc:9000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin'
header is present on the requested resource.
Copy the code

Cause: The vite-plugins-mock middleware will execute res.end() and rewrite the header of response, causing the cross-domain plug-in before the vite-plugins-mock plug-in to be invalid.

The solution is as follows (rewrite the response of the mock data).

Enhance mock data
function enhanceResponseFn(responseFn: IResponseFn) :IResponseFn {
  return function(url, body, query, headers) {
    const res = this.res
    const req = this.req
    if (res) {
      res.setHeader('Access-Control-Allow-Credentials'.'true')
      res.setHeader(
        'Access-Control-Allow-Origin',
        req.headers.origin || DEV_ORIGIN.origin
      )
      res.setHeader(
        'Access-Control-Allow-Methods'.'POST, GET, OPTIONS, DELETE, PUT'
      )
      res.setHeader(
        'Access-Control-Allow-Headers'.'Origin, X-Requested-With, Content-Type, Accept, If-Modified-Since')}return responseFn.call(this, url, body, query, headers)
  }
}

/** plugin-mock is used to solve cross-domain problems caused by mocks. * vite-plugin-mock prefixes res.end to cause cross-domain restrictions on the mock interface that calls the current child application in the main application *@param mockData 
 * @returns * /
export function enhanceMockData(mockData: IMockDataList) :IMockDataList {
  return mockData.map((data) = > {
    const {
      url,
      method,
      response
    } = data
    return {
      url,
      method,
      response: enhanceResponseFn(response),
    }
  })
}
Copy the code

4.5, routing,

The route guard triggered multiple times

  • History conflicts with single-SPA. A single callback is repeated twice, causing umi and Qiankun to behave abnormally #3919 when used together

Clicking the navigation menu of the sub-application will cause the page request of the current module to be cancelled.

  export const clearPending = () = > {
    for (const [url, cancel] of pending) {
      cancel(url)
    }
    pending.clear()
  }
  service.interceptors.request.use((config: AxiosRequestConfig) = > {
    removePending(config) // Check and cancel the previous request before the request starts
    addPending(config) // 
  })
  / / error
  // Route jump is executed twice
  router.beforeEach((to, from, next) = > {
    console.log('Child application: router. BeforeEach');
    clearPending()
    next()
  })
Copy the code

The router add base

Adding a base to a router using vue-router API in an application may cause problems

  1. The parent application’s Router hook alerts you (twice, the first time), as in/#/micro-app-mis/store/listTo report to the police/store/listDoes not exist;
  2. The child application is mounted repeatedly, and the mounted function is executed.

4.6. Js isolation

LocalStorage isolation

Vuex-persistedstate is used in the project to implement vuex persistent cache. Because Localstorage is not isolated, vuex cache conflicts occur between sub-applications.

CustomElements definition conflict

Vite service added in the development environment reported an error @vite/client, blocking page rendering. The sub-application vite version was upgraded from 2.3.7 to 2.6.10, and the following error message was reported:

  overlay.ts: 185 Uncaught( in promise) DOMException: Failed to execute 'define'
  on 'CustomElementRegistry': the name "vite-error-overlay"
  has already been used with this registry
  at http: //test.suanshubang.cc:3000/static/fe-store-mis/@vite/client:178:16
Copy the code

For example, the customElements.define() function creates a component with the same name in the child and parent applications, causing an error.

  class PopUpInfo extends HTMLElement {
    constructor() {
      // The super method must be called first
      super();
    }
  }
  // Child application
  customElements.define('popup-info', PopUpInfo);
  // In the parent application
  customElements.define('popup-info', PopUpInfo);

  // VM34:7 Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': the name "popup-info" has already been used with this registry
  at < anonymous >: 7: 16(anonymous) @ VM34: 7
Copy the code

Apm monitoring

When the master application APM “performance Monitoring” and “User Behavior analysis” were connected, due to the isolation mechanism of Qiankun, when the sub-application was opened in the master application, the “application ID” in the APM-related data reported by the master application would be rewritten as the “application ID” of the sub-application, resulting in the failure of the master application to report data.

In the current processing method, apM “Performance Monitoring” and “User behavior analysis” of sub-applications were temporarily removed, while MDIAN system “performance data” statistical indicators related to “front-end horizontal topic communication” were unified using the performance indicators of the qiankun main application.

The APM team is working on “multi-instance”, which can be accessed after the function is improved. That is, the main application and sub-application only have their own APM instances to avoid conflicts.

4.7 Resource Loading

In Qiankun, the logic to load parsing sub-applications was implemented in import-HTml-Entry.

Refer to a previous blog post, 🐶 interesting BUG — Last-Modified hit strong cache.

4.8, other

Subapplication split

Functional units with close business connection should be made into one micro-application, whereas those with weak business connection can be divided into multiple micro-applications. One criterion for determining whether the business is closely related is whether this micro-application has frequent communication requirements with other micro-applications.

Principle 5,

5.1 Add the CSS prefix to sub-applications

Qiankun provides an experimental style isolation characteristics, when experimentalStyleIsolation is set to true, qiankun son will rewrite the application style for all style rules to increase the added a special selector rules to limit the scope of its impact.

The Qiankun would mount the styleNode node to a temporary swapNode and run this.rewrite to add the class prefix

mount

function getOverwrittenAppendChildOrInsertBefore() {
  return function appendChildOrInsertBefore < T extends Node > () {
    switch (element.tagName) {
      case LINK_TAG_NAME:
      case STYLE_TAG_NAME: {
        // enter here
        css.process(mountDOM, stylesheetElement, appName);
      }
      returnrawDOMAppendOrInsertBefore.call(mountDOM, stylesheetElement, referenceNode); }}}return rawDOMAppendOrInsertBefore.call(this, element, refChild);
};
}
Copy the code

CSS object

rawDocumentBodyAppend.call(document.body, styleNode)
this.swapNode = styleNode;
this.sheet = styleNode.sheet! ;this.sheet.disabled = true;
Copy the code

css.process

const textNode = document.createTextNode(styleNode.textContent || ' ');
this.swapNode.appendChild(textNode);
const sheet = this.swapNode.sheet as any; // type is missing
construles = arrayify < CSSRule > (sheet? .cssRules ?? []);const css = this.rewrite(rules, prefix);
// eslint-disable-next-line no-param-reassign
styleNode.textContent = css;
Copy the code

rewrite

private rewrite(rules: CSSRule[], prefix: string = ' ') {
  let css = ' ';

  rules.forEach((rule) = > {
    if (rule.cssText.includes(`el-dialog__header`)) {
      console.log(css)
      debugger;
    }
    switch (rule.type) {
      case RuleType.STYLE:
        css += this.ruleStyle(rule as CSSStyleRule, prefix);
        break;
      case RuleType.MEDIA:
        css += this.ruleMedia(rule as CSSMediaRule, prefix);
        break;
      case RuleType.SUPPORTS:
        css += this.ruleSupport(rule as CSSSupportsRule, prefix);
        break;
      default:
        css += `${rule.cssText}`;
        break;
    }
    if (rule.cssText.includes(`el-dialog__header`)) {
      console.log(css)
      debugger; }});return css;
}
Copy the code

5.2, the sand box

  • LegacySandbox (single-instance Proxy);
  • ProxySandBox (multi-instance Proxy, default);
  • SnapshotSanBox (Window snapshot, degraded);

The implementation principle is as follows:

const proxyWindow = new Proxy(window, {
  get(target, p) {
    console.log('get');
    return Reflect.get(target, p);
  }
  // ...
})

;(function(window, self) {
  with(window) {
    // code
  }
}.bind(proxyWindow)(proxyWindow, proxyWindow))
Copy the code

Partial source code (source code in import-grom-Entry plug-in) :

/ / generated code
function getExecutableScript(scriptSrc, scriptText, proxy, strictGlobal) {
  const sourceUrl = isInlineCode(scriptSrc) ? ' ' : `//# sourceURL=${scriptSrc}\n`;

  // Get the global window in this way. Since script is also run in the global scope, we must ensure that the window.proxy binding is bound to the global window as well
  // In nested cases, window.proxy is set to the inner application's Window, while the code actually runs in the global scope. This will cause the window.proxy in the closure to take the outermost microapplication's proxy
  const globalWindow = (0.eval) ('window');
  globalWindow.proxy = proxy;
  // TODO switches with closure through strictGlobal and merges with closure after strictGlobal
  return strictGlobal ?
    `; (function(window, self, globalThis){with(window){;${scriptText}\n${sourceUrl}}}).bind(window.proxy)(window.proxy, window.proxy, window.proxy); ` :
    `; (function(window, self, globalThis){;${scriptText}\n${sourceUrl}}).bind(window.proxy)(window.proxy, window.proxy, window.proxy); `;
}

/ / code execution
evalCode(scriptSrc, code);
Copy the code

6,performance

  • [RFC] Ultra-performance optimization of Qiankun, import-HTML-Entry
  • [Feature Request] Would it be better to proxy document in sandbox? # 1175

Vue2

Simple script execution performance is fine by a factor of 1-1.2, but when it comes to DOM manipulation, performance deteriorates dramatically.

With 10,000 DOM nodes, the difference would be more than 10 times.

100,000 DOM nodes is probably 20-30 times worse.

Vue3

Almost no difference

<template> <div class="pt60"> <ul class="wrapper"> <li v-for="item in aaa" :key="item">{{ item }}</li> </ul> <button @click="test">test</button> </div> </template> <script>; export default { data() { return { aaa: 1 }; }, methods: { test() { console.time("run loop", 100000); for (let index = 2; index < 1 * 100000; index++) { this.aaa = index; } console.timeLog("run loop", 100000); this.$nextTick(() => { console.timeEnd("run loop", 100000); }); }}}; </script>Copy the code

7, extension,

  • The vue<style> scopedImplementation;
const moduleId = 'data-v-' + hash(isProduction ? (shortFilePath + '\n' + content) : shortFilePath)
// Relative path + content: relative path
Copy the code

8, reference

  • qiankun
  • Micro Frontends
  • Detailed analysis of micro front end, micro front end framework Qiankun and source code
  • Principle and practice of micro front end framework qiankun
  • You probably don’t need the microfront-end
  • Probably the most complete microfront-end solution you’ve ever seen
  • JavaScript Read source series-import-HTmL-entry for the micro front end