The main research object qiankun explored the internal principle

A brief introduction of Qiankun

1. Install

$ yarn add qiankun # or NPM I Qiankun-s
Copy the code

2. Register the active application

registerMicroApps([
    {
        name: 'reactApp'.entry: '//localhost:3000'.container: '#container'.activeRule: '/views/app-react'}, {name: 'vueApp'.entry: '//localhost:8080'.container: '#container'.activeRule: '/views/app-vue'}, {name: 'reactApp2'.entry: 'http://localhost:9100/react-app2/template/index.html'.container: '#container'.activeRule: '/views/app-react2',}]);/ / start qiankun
start();
Copy the code

Once the url of the browser changed after the microapplication information was registered, the matching logic of qiankun would be automatically triggered. All microapplications matched by activeRule rules would be inserted into the specified Container and the lifecycle hooks exposed by the microapplication would be called in turn. If the subapplication has child routes, you need to configure basename of the subapplication route

3. Transformation of sub-applications

Export lifecycle hooks

Microapplications need to export the bootstrap, mount, and unmount lifecycle hooks in their own entry JS (usually webpack entry JS) to be called by the host application at the appropriate time

/** * Bootstrap will only be called once during the micro-application initialization. The next time the micro-application re-enters, the mount hook will be called directly. Bootstrap will not be triggered again. * This is usually where we can initialize global variables, such as application-level caches that will not be destroyed during the unmount phase. * /
export async function bootstrap() {
  console.log('react app bootstraped');
}

/** * The application calls the mount method every time it enters, and usually we trigger the application's render method here */
export async function mount(props) {
  ReactDOM.render(<App />, props.container ? props.container.querySelector('#root') : document.getElementById('root'));
}

/** * The method that is called each time the application is cut/unloaded, usually here we unload the application instance of the microapplication */
export async function unmount(props) {
  ReactDOM.unmountComponentAtNode(props.container ? props.container.querySelector('#root') : document.getElementById('root'));
}

/** * Optional lifecycle hooks that only work when microapplications are loaded using loadMicroApp */
export async function update(props) {
  console.log('update props', props);
}
Copy the code

Modify the Webpack configuration

  1. newpublic-path.jsFile and referenced at the top of the entry file to modify the publicPath at run time
  2. To allow development environments to be packaged across domains and UMD, modify webPack packaging:
const packageName = require('./package.json').name;

module.exports = {
  output: {
    library: `${packageName}-[name]`.libraryTarget: 'umd'.jsonpFunction: `webpackJsonp_${packageName}`,}};Copy the code

About the description of the public – path can see this document: webpack.docschina.org/guides/publ…

About the description of the library can refer to this document: webpack.docschina.org/guides/auth…

The use of single – spa

The main function of single-SPA is to realize route hijacking and application loading, but does not realize JS and CSS isolation

Principle of Qiankun qiankun

Before studying the principle of Qiankun, we should try to ask some questions and find the answers in the process of reading the source code. For Qiankun, we are concerned about the following issues:

  • qiankunwithsingle-spaWhat is the relationship?
  • qiankunHow to implement JS sandbox?
  • qiankunHow do I implement CSS isolation?

registerMicroApps

The first step in configuring the microapp is to register the sub-app in the main application and configure its name, entry, DOM container, and wake up condition. The sub-app will then be mounted to the DOM container according to the wake up condition.

  1. Usage: registerMicroApps(apps, lifeCycles?)
    • Parameters:
      • apps – Array<RegistrableApp>– Mandatory. Some registration information about the micro application
      • lifeCycles – LifeCycles– Optional, global microapplication lifecycle hooks
    • Break down
      • RegistrableApp
        • name – stringN/A Mandatory. The name of the micro application must be unique
        • entry – string | { scripts? : string[]; styles? : string[]; html? : string }– Mandatory, micro application entry
        • container – string | HTMLElement– Mandatory, micro – application container node selector orElementInstance. Such ascontainer: '#root'container: document.querySelector('#root')
        • activeRule – string | (location: Location) => boolean | Array<string | (location: Location) => boolean>N/A Mandatory: Specifies the activation rule for the micro application
        • loader – (loading: boolean) => void– optional,loadingMethod that is called when the state changes
        • props – object– Optional. Data that the master application needs to pass to the microapplication
      • LifeCycles
        • beforeLoad – Lifecycle | Array<Lifecycle>– optional
        • beforeMount – Lifecycle | Array<Lifecycle>– optional
        • afterMount – Lifecycle | Array<Lifecycle>– optional
        • beforeUnmount – Lifecycle | Array<Lifecycle>– optional
        • afterUnmount – Lifecycle | Array<Lifecycle>– optional
  2. The sample
import { registerMicroApps } from 'qiankun';

registerMicroApps([{
    name: 'app1'.entry: '//localhost:8080'.container: '#container'.activeRule: '/react'.props: {
        name: 'kuitos'}}, {beforeLoad: app= > console.log('before load', app.name),
    beforeMount: [
        app= > console.log('before mount', app.name)
    ]
});
Copy the code
  1. Implementation principle: Behind the callsingle-spatheregisterApplicationMethod, here the main work inregisterApplicationtheappProcessing in parameters:
registerApplication({
    name,
    app: async () => {
        loader(true);
        await frameworkStartedDefer.promise;
        const{ mount, ... otherMicroAppConfigs } = (awaitloadApp({ name, props, ... appConfig }, frameworkConfiguration, lifeCycles) )();return {
            mount: [async () => loader(true), ...toArray(mount), async () => loader(false)],
            ...otherMicroAppConfigs,
        };
    },
    activeWhen: activeRule,
    customProps: props,
});
Copy the code

LoadApp is the core, repackaging the mount and unmount methods of single-SPA required Applicat, adding some additional operations to each lifecycle. For example, beforeMount and afterMount callbacks are executed, and mountSandbox is used to enable sandbox. BeforeUnmount, afterUnmount callbacks, and unmountSandbox release sandbox are performed when unmount.

  • How did Qiankun achieve the sandbox?

    Generate a sandbox by calling createSandboxContainer, using Proxy if the current browser environment supports Proxy and snapshot if not. For Proxy mode, createFakeWindow(rawWindow) is first called to generate a fakeWindow copy of the original window

LoadApp function principle

Executes the app method passed in when the user calls registerApplication to load the application

  1. callimport-html-entryThe moduleimportEntryFunction to get the HTML file, executable script file, and publicPath of the corresponding child application
  2. callgetDefaultTplWrapperUse the HTML content of the child applicationdivTag up
  3. callcreateElementThe HTML () function generates the child application HTML after the HTML, body, and head tags are removedinnerHTMLAchieve filtering effect)
  4. callgetRenderThe function yields the render function
  5. Call render from step 4 to empty the container and render the child application’s DOM elements onto the specified Contanter element
  6. callgetAppWrapperGetterFunction that gets the processed child application DOM elementsinitialAppWrapperGetterFor future use of child application DOM elements
  7. ifsandboxIf true, callcreateSandboxContainerfunction
  8. performexecScriptsFunction to execute the subapplication script
  9. performgetMicroAppStateActionsFunction, getonGlobalStateChange,setGlobalState,offGlobalStateChangeIs used to pass information to a parent application
  10. performparcelConfigGetterFunction, wrappermountandunmount

CreateSandboxContainer function principle

RegisterApplication function principle

  1. Regularization parameters, registerApplication parameters have two forms. First, the different parameter forms are reduced to the same format{name,loadApp,activeWhen,customProps}
  2. Detection registeredappNameWhether the same name, the same name will throw an exception
  3. willapplicationConfiguration is pushed into the global arrayappsKept in
  4. If it is a browser environment (based on the presence of the window variable) then:
    1. Make sure to introducejQueryUnder the premise ofwindow.jQueryTo be able to use
    2. performrerouteFunction and do the following:
      1. traverseappsArray, getNOT_MOUNTED,MOUNTED,LOADING_SOURCE_CODEtheapplication
      2. Check whether the execution is performedstartMethod, if it has already been executed (such as switching routes on a page)performAppChangesFunction, and vice versaloadAppsFunction (when the page is refreshed for the first time)

The performAppChanges function works

Use promise.resolve ().then() to execute all code within the function asynchronously

  1. usingwindow.dispatchEventandCustomEventThe triggersingle-spa:before-no-app-changeorsingle-spa:before-app-changeAs well assingle-spa:before-routing-eventEvent (these two interfaces are not supported by IE)
  2. Execution queueappthemountandunmountOperation (The specific operation needs further study)

Principle of start function

Starting qiankun, you can pass in some configurations such as how to get resources and whether to use sandboxes

  1. For usage see: qiankun.umijs.org/zh/api#star…
  2. Implementation principle: Behind the callsingle-spathestartMethod, executionrerouteorsetUrlRerouteOnlyfunction

The appendix

The resources

  • Qiankun Technology Roundtable
  • Implementing a front-end microservice from 0 (part 1)
  • Implementing a Single-SPA front-end Microservice from 0 (middle)
  • Implementing a Single-SPA Front-end Microservice from 0 (part 2)
  • Practice and summary of Qiankun micro front end scheme
  • Summary of Qiankun Micro-front-end Practice (II)
  • Thinking in Microfrontend
  • A brief introduction to single-SPA and a summary of the problems encountered
  • There are three implementations you need to know about microfronts
  • Learn JS modularity from using SystemJS