With the improvement of micro-front-end architecture, front-end engineering is no longer limited to the traditional megalithic application development, but draws on the development idea of back-end micro-servitization, and front-end development is more and more close to the development mode of micro-front-end. How to achieve seamless connectivity in umi, the most popular React framework? Here is how to quickly integrate the Qiankun framework into UMI.

Umi’s strength, in addition to its out-of-the-box, internal integration of ANTD + DVA and other family barrels, another strength is its plug-in system, not surprisingly, qiankun is also among them, see # @umijs/ plugin-Qiankun; Basic enabling methods are not explained here. You only need to follow the official website to integrate QIANkun into UMI perfectly through simple steps.

This article mainly discusses two questions:

  1. How to implement dynamic registration (Registration menu and Dynamic route registration)
  2. The master applies the communication scheme

How to implement dynamic registration

Static registration can be easily implemented in accordance with the official website documentation, directly in the config.ts file to write the master application configuration, so when should we consider dynamic registration scenario?

  1. Access control
  2. Dynamic conditions exist when the current application is uncertain

Both of them have one thing in common: they rely on interfaces, cannot know the specific child application and its number until the back-end interface returns, or the hard-coded approach brings a series of bad interaction experiences. In the first scenario, although we can enter each sub-application through static registration, each sub-application will judge whether it has the access permission according to the permission. If it does not, it will be redirected to XXX page. This is not recommended because it brings up two deadly points. First, each sub-application needs to add interception processing separately to determine whether it has access permission. Not to mention the problem of code redundancy, whether the permission data is requested separately or passed through the master application needs to be considered separately. Second, from the perspective of users, it is not good to enter the page first and then jump to the right limit. Add the following to app.tsx:

Export Async function qiankun() {const rs: any = {apps: [], // routes: [], // react-router, {name: xxx, path: xxx, icon: xxx } lifeCycles: { afterMount: (props: any) => { console.log(props); ,}}}; const res: any = await queryMenuList(); If (res.statusCode === '200' && res.datas? .length) { const menuList = res.datas[0].children; const { apps, routes } = parseMenu(menuList, query); rs.apps = apps; rs.routes = routes; } return Promise.resolve(rs) }Copy the code

The advantage of this approach is that not only the child application, but also the route can be registered dynamically. All the interception configuration is neatly folded into the master application, and the child application does not need to make any task changes. Using this approach can be a perfect solution to the dynamic registration of sub-applications and routes, will there be any problems? The answer is yes. According to umi’s openness principle, static configuration is generally maintained in config.ts, and dynamic runtime configuration is maintained in app. TSX. Registration information in the configuration is only executed once during initialization, and then will not be executed again. But there is no end to human desire, and suddenly one day, there is a request to say, I want to add a XXX button, click the button and reload the configuration again. You might say that’s not so hard, since it’s only done once, just reload it again. I was stumped when the requirement asked if I could load dynamically without refreshing. The article writes this, that certainly is to have the method that solves, otherwise throw out this problem is to denounce call?

Since qiankun was integrated through plug-in system, can we start from this idea and see how the plug-in was called during initialization and the method of Qiankun in APP.TSX was implemented? As a front-end expert, I added a console.trace(‘ Qiankun call stack ‘) to qiankun(), and finally found an interesting plugin: plugin.applyPlugins.

import { history, plugin, ApplyPluginsType } from "umi"; import { setMasterOptions, getMasterOptions } from "@@/plugin-qiankun/masterOptions"; function reloadSetting() { const config = await plugin.applyPlugins({ key: 'qiankun', type: ApplyPluginsType.modify, initialValue: {}, args: {}, async: true, }); const masterOptions = { ... getMasterOptions(), ... config}; console.log('masterOptions', masterOptions, ) setTimeout(() => { setMasterOptions(masterOptions); }}, 0)Copy the code

The implementation of reloadSetting method re-executed the Qiankun method and reloaded the latest configuration. However, as a professional engineer, could he be so hasty? Indeed, a problem was found after a log printing. Although dynamic sub-applications and route registration can be realized in the Qiankun method, it is additive rather than overlay, and the route volume will increase ………… every time it is executed Finished, the instant feel oneself roll not to move, dug a big pit for oneself again, can regret to leave a sentence, although this thing is good, please use cautiously, do not know big gods have what solution?

The communication between the host and its application is abnormal

  1. UseQiankunStateForSlave + useModel, see: Access
export function useQiankunStateForSlave() { const { userInfo }: any = useModel('@@qiankunStateFromMaster') || {}; const [data, setData] = useState(); FetchData (). Then ((res) => {setData(res)}) return {data, setData, userInfo,}; }Copy the code
  1. MicroAppWithMemoHistory
import React from 'react'; import { MicroAppWithMemoHistory } from 'umi'; import styles from './index.less'; interface Props { name: string; url: string; dataProps: any; [key: string]: any; } const MicroApp = (props: Props) => { const { name, url, ... restProps } = props; return ( <div style={{height: '100%'}}> <MicroAppWithMemoHistory className={styles.microApp} name={name} url={url} style={{height: '100%'}} {... restProps} /> </div> ) } export default MicroApp; <MicroApp name='name' url='url' dataProps={{}}/>Copy the code

The advantage of using MicroAppWithMemoHistory is that you can access a specified page of a specified subapp, that is, specify which page to visit by url; The second is that the child application can be mounted anywhere, for example:

const Page = (props: Props) => { const { name, url, ... restProps } = props; return ( <div style={{height: '100%'}}> <div className='left'> // Here is the sidebar <SiderBar> </div> <div className='right'> <h1> Here is the title </h1> <div> // here is where the child application is rendered  <MicroAppWithMemoHistory className={styles.microApp} name={name} url={url} style={{height: '100%'}} {... restProps} /> </div> </div> </div> ) } export default Page;Copy the code

Other communication methods have not been tried too much for the time being, but some inspiration from the above example is that the basic principle of transparent transmission for the master application is to expose a global model, and then the child application is mostly consumed through useModel. The advantage of this is to achieve real-time refresh. So the idea of transparent transmission can be in how to integrate into the global model, the specific implementation is not to investigate, estimate and have to do a wave of source code.

conclusion

  1. Umi’s support for Qiankun was already high, and with its plug-in system, the transformation cost was small
  2. There is also a complete solution for communication between master and child applications. By sharing data with global model, useModel is consumed. Compared with IFrame, useModel is much more efficient and does not have to consider various cross-domain problems
  3. Through personal practice, I found that there are still some problems, such as the style isolation is not completely isolated, in the multi-tab scene and multiple sub-applications coexist, there will still be style influence, at present, in the isolation layer, each sub-application still needs to add CSS scope through CSS module to carry out isolation. But it gets better anyway, right