This article has participated in the call for good writing activities, click to view: back end, big front end double track submission, 20,000 yuan prize pool waiting for you to challenge!

preface

This article is another version of the story in which I finally sent you to dachang. The emotional line and technical line of this article will be more delicate, please read it carefully.

0. Business solutions

My name is Yiyi Bai.

“Xiao Bai, understand some commercial solutions to go.”

I looked at my copy of Small White Business Solutions on my desk for a long time. That didn’t upset me for an hour, the boss told me, until I saw the printout on the desk. You said the “little White” on the cover was an accidental joke, right? Well, business solutions sounds like the kind of territory only industry titans should be in.

Me, white, and true white are almost the same…

I secretly chagrin, in the mind ridicule eldest brother, say a word can not be clear. I turned to the first page, and in big bold letters I read: Microfront-end Architecture.

Microfront-end architecture

Let’s start with a picture of a beautiful chestnut.

Does it look that complicated?

  • Basic capability layer
    • Basic skills. For example, permission management (you can see what role you own)
  • Product function layer
    • Specific requirements function realization. For example, the data analyst role comes into your platform to see the analysis report
  • Business solution layer
    • Divide into different regions by business
  • Related systems
    • How many systems does your platform integrate?

(Here, it doesn’t matter if you don’t understand. Keep a concept in mind and see what other people’s microfront-end architects are based on.

To recap, what is a microfront-end architecture?

  1. Business-independent content that assists in accessing the product is placed in a container.
  2. Achieve product function related, can be multiple containers.
  3. Make a function set for different products to form different business schemes.
  4. 1-3 can be implemented as a system. Repeat 1 to 3 for multiple systems.

(So far, it doesn’t matter if you don’t understand. Say it again.

  • Suppose you have a front-end project (main application) that does nothing but one thing. That is, the ability to access different systems is integrated together, matching roles can successfully access the corresponding content.

  • Then you have a lot of front-end projects (microapplications) where there’s nothing but product functionality, no permissions, no role correctness. For example, you have mall systems, in-store systems, supply chain systems, etc. Each system can then have many products distributed across different microapplications.

(At this point, it doesn’t matter if you still feel unspoken. Reanalyze it)

Investigation of various schemes

plan introduce advantage disadvantage
1. iframe </div> 1. Low development and introduction costs. 1. Communication difficulties in master/micro applications
2. High compatibility 2. The internal hop is unfriendly, for example, the login hop
3. Good isolation 3. Components and modules cannot be reused
2. NPM integration Break up the sub-projects into packages and publish them to NPM, importing dependencies for whoever wants to use them. 1. No extra resources need to be loaded during compilation and project running, so the experience will be smooth 1. The compilation speed and packaged volume of the main application tend to be too large
2. Low cost of development and access 2. The NPM package does not support dynamic delivery and is loaded on demand. After the NPM package is updated, the main application needs to be released again
3. single-spa/qiankun Route changes drive the master application to load the bundle of the microapplication and render it to the specified node 1. Complete isolation mechanism, such as sandbox. Can isolate style, JS script. 1. High cost of communication between micro applications
2. The primary application does not restrict the technology stack that accesses the application 2. Additional management of microapplications is required
4. Module federation Webpackage 5 new function plug-ins, module federation, component federation Maximize module, component liberalization, decentralization Too much freedom, still too little management

So it looks like Qiankun is better suited for app-level integration. Module federation. Greater integration of module/component granularity

Qiankun simple analysis source code

  • Initialize the global configuration
    • Register child applications registerMicroApps(apps, lifeCycles?)
    • The import-html-entry library is used to load the child application from entry. After loading the child application, it will return an object: {}
     const {template,execScript,assetPublicPath,getExternalScripts,getExternalStyleSheets} = await importEntry(entry,{
                    getTemplate:flow(getTemplate,getDefaultTplWrapper(appName)), ... settings })console.log(template()); / / = > 
             ... 
                console.log(getExternalScripts()); // Get the js script list
    
                 [
                     / * * * * * * /(function(modules){/* webpackBootstrap... / * * * * * * * /}) (),/ * * * * * * /(this["webpackJsonP_react"] = this['webpackJsonP.r' / * * * * * * /]),... ] * * /console.log(getExternalStyleSheets()) ; // => [] Style sheet CSS
    
                 // Then we will examine the execScripts method, which specifies a proxy object (window by default), executes all the JS in the template file, and returns the last property of the proxy object after JS execution
                 // In a microfront-end architecture, this object typically contains the lifecycle hook functions of the child applications. The main application can mount and destroy the child applications by calling these lifecycle hook functions at a specific stage.
    Copy the code
    • The primary application mounts the HTML template of the child application
    • Sandbox runtime environment – genSandbox
                // genSandbox
                export function genSandbox(appName: string,singular: boolean){...let sandbox: SandBox;
                    if(window.Proxy){
                        sandbox = singular ? new ProxySandBox(appName): new LegacySandBox(appName)
                    }else{
                        sandox = new SnapshotSandbox(appName)
                    }
                    ...
                }
                // genSandbox is divided into ProxySandbox and SnapshotSandbox, depending on whether window.Proxy is supported.
    
              /** * Diff - based sandbox for older browsers that do not support Proxy */
                export default class SnapshotSandbox implements SandBox {
                    proxy: WindowProxy;
                    name: string;
                    type: SandBoxType;
                    sandboxRunning: boolean;
                    private windowSnapshot;
                    private modifyPropsMap;
                    constructor(name: string);
                    active(): void;
                    inactive(): void;
                }
                // The sandbox environment of SnapshotSandbox is mainly achieved by taking a snapshot of the Window state when activated and restoring the Window object when closed
    Copy the code
    • Mounting a sandbox – mountSandbox
    • Timer hijacking – patchTimer
    • Dynamically add stylesheets and script files hijack – patchDynamicAppend
    • UnmountSandbox – unmountSandbox
    • Do not write, again you will not see 😂
    • Register internal lifecycle functions
    • The mount process is displayed
    • The unmount process is displayed
  • Start the main application (opTS?)

So, did you understand Qiankun?

step 1: The master application obtains the HTML template, JS script and CSS style sheet of the micro application first.

step 2: Mount microapplication resources

step 3: Registration life cycle

Module federal

The use of the ModuleFederationPlugin
new ModuleFederationPlugin({
  name: "app1".library: { type: "var".name: "app1" },
  filename: "remoteEntry.js".remotes: {
    app2: 'app2'.app3: 'app3',},remoteType: 'var'.exposes: {
    antd: './src/antd'.button: './src/button',},shared: ['react'.'react-dom'].shareScope: 'default'
})
Copy the code

Configuration properties:

  • name, must, unique ID, as the output module name (container), when used throughname/{name}/name/{expose}Is used in the manner of;
  • library, optional, packaging mode, default{ type: "var", name: options.name }, where herenameasumd çš„ nameIs the name of the variable to be mounted globally;
  • filename, optional, the name of the packaged file.
  • remotes, indicating that the current application is a Host and can reference the Expose module of Remote.
  • remoteType, optional, default var,("var"|"module"|"assign"|"this"|"window"|"self"|"global"|"commonjs"|"commonjs2"The external type of the remote container;
  • exposes, optional: indicates that the current application is oneRemote.exposesThe inside module can be replaced by the otherHostThe reference mode isimport(name/{name}/name/{expose});
  • shared, optional, mainly used to avoid multiple public dependencies in the project. If this attribute is configured, WebPack will first determine whether the corresponding package exists in the local application during loading. If not, the dependency package of the remote application will be loaded.
  • shareScopeOptional, share scope name used for all share modules
// Common dependencies on shared configuration itemsShared = string[] | { [string]: { eager? : boolean;// Whether to load the module immediately instead of asynchronously
    import? :false | SharedItem; // The module that should be supplied to the shared scope. Also acts as a fallback module if the shared module is not found in the shared scope or the version is invalid. The default is the property namepackageName? : string;// Set the package name to find the desired version. Do this only if the package name cannot be automatically determined based on the request (set requiredVersion to false to disable automatic inference).requiredVersion? :false | string; // Version requirements for modules in the shared scopeshareKey? : string;// Use this name to find modules in the shared scopeshareScope? : string;// Share scope namesingleton? : boolean;// Whether only one version of a shared module is allowed in the shared scope (singleton mode).strictVersion? : boolean;// Shared modules will not be accepted if the version is invalid (default true if the local rollback module is available and the shared module is not a singleton, otherwise false, invalid if the required version is not specified)version? :false | string; // The version of the supplied module will replace the lower matching version}} []Copy the code

Type on the blackboard and underline! When using Module Federation, it is important to configure common dependencies into shared. In addition, you must configure shared for both projects, otherwise an error will be reported

The principle of ModuleFederationPlugin

The ModuleFederationPlugin does three main things:

  • How to share dependencies: Use SharePlugin. The plug-in makes common dependencies shareable

  • How to expose modules: Use ContainerPlugin. This plug-in creates an entry for the specified public module. Entry. js’ ‘suspends an object on the window, which has two methods, get and init. The get method is used to get modules. The init method is used to initialize the container, which can provide shared modules.

    // Get and init methods in remote objects
    var get = (module, getScope) = > {
        __webpack_require__.R = getScope;
        getScope = (
            __webpack_require__.o(moduleMap, module)? moduleMap[module] () :Promise.resolve().then(() = > {
                    throw new Error('Module "' + module + '" does not exist in container.'); })); __webpack_require__.R =undefined;
        return getScope;
    };
    var init = (shareScope, initScope) = > {
        if(! __webpack_require__.S)return;
        var oldScope = __webpack_require__.S["default"];
        var name = "default"
        if(oldScope && oldScope ! == shareScope)throw new Error("Container initialization failed as it has already been initialized with a different share scope");
        __webpack_require__.S[name] = shareScope;
        return __webpack_require__.I(name, initScope);
    };
    // This exports getters to disallow modifications
    __webpack_require__.d(exports, {
        get: () = > get,
        init: () = > init
    });
    Copy the code

When using the module of Remote, init was used to write its shared into the Remote, and then get the expose component of the Remote. When using the Remote, determine whether there are available shared dependencies in the Host. If so, The Host dependency is loaded. If no Host dependency is loaded, the Host dependency is loaded.

ContainerReferencePlugin:

This plug-in adds specific references to containers that are external resources (externals) and allows remote modules to be imported from these containers. The remote provided by the container consumer is called to reload the import.

Modules defined by remotes are also declared in __webpack_modules__ but not implemented, just like asynchronous imports. The __webpack_require__.e method has been added to webpack5, which executes the following three functions on modules imported through this method and returns only after all of them are successful.

  • __webpack_require__.f.consumesIt is used to identify and consume shared modules, and does not make remote requests if the module is already present in the current environment
  • __webpack_require__.f.remotesUsed to connect containers
  • __webpack_require__.f.jTo load JS

1. There is still a problem on the line, urgent release.

It was windy that day. At 3 or 4 o ‘clock in the afternoon, it was dark and scared the baby to death.

“Oh, join in the fun? Have you got an umbrella? Would you like a cup of my new coffee?”

The boss’s kind face is just too much to hate. I learned a week, every night to see the source code, eye black circle are heavy several rounds. I was thinking, is it that bitter? On Monday morning, the boss publicly announced that we were going to do progressive micro front-end architecture, and I was in charge. I’m almost broken.

There were only five people scheduled, and I spent every day in a state of extreme anxiety, literally breaking from head to toe! This week just came to the period, the head drowsy just want to sleep, see people want to temper. You mean I give up? Useful? The boss is really that kind of guy. If I don’t do this right, he’ll tell me to go…

On launch day, I was surprised to find that the beta didn’t bother me at all. After working overtime for a week, I succeeded, but my period didn’t go at all. I’m a little uneasy…

The emergency room.

“Eldest brother, successful line?”

“Well.”

“Boss, no bugs?”

“No.”

“Boss, the hospital smells terrible.”

“The smell of disinfectant.”

“Boss, why are you kicking me out?”

“Send you away? What do you mean?”

“You said: xiao Bai, understand some commercial solutions to go.”

“Oh. I told you to get yourself out of the water-cooler before they caught you fumbling.”

Wow… 555555.

I couldn’t help falling apart. On the one hand, I feel aggrieved. On the other hand, I feel relieved.

“You this may be endometrial inflammation, have to do gynecological examination. Small white will come soon, you usually pay attention to rest.”

Heartless! Indifference! The eldest brother did not comfort, went out to pick up small white.

Xiao Bai came and turned livid. I knew something was wrong, and I was the one who could be wrong tonight.

“Xiao Bai, are you ok? Oh, my God, you don’t care about yourself. Which can not pay attention to rest during the period, crazy overtime?”

“The eldest brother gave me the task did not complete!”

Little White is not silent. Well, I’m pretty sure the boss is back on an emergency release.

Front-end visualization solutions

To be continued. I’m on my period. I can’t write.