“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”


The product proposes that the system should be modularized, building our applications through a combination of different modules. Isn’t this a very popular micro front end recently? After some communication with friends in the group, I started to build it under pressure. After three months of iterative development, two modules were migrated into sub-applications while the business was being developed. The system is online, and the hanging heart is finally down.

Analysis of existing system status

The existing system is a separate project, developed using the UMI framework, with folders separating the major business modules. Common groups are managed through NPM packages. Due to the long iteration time of the system, several remaining problems on the architecture need to be solved

  • The subapplication uses ANT4.x(AntD uses 3.x version, it is difficult to upgrade ANTD4.x, mainly because the Form changes a lot)
  • Hooks replace part state of redux(There are almost a hundred states in the Redux stroe, and some states that shouldn’t be in the redux are included.)
  • Unified packaging REQUST(Split into separate HTTP and Socket request libraries, which support hooks)

The first landing version of the architecture

Introduce the micro front end to solve the problem

  • encapsulationThe scaffold
  • Component libraryupgradeTo supportantd4.x
  • Master the applicationcommunication
  • The main applicationSharedSome of theThe instanceFor use by sub-applications
  • Redux Store tooPart of the dataNeed to beSharedHow do you limit it
  • Sub-applications support internationalization, internationalization contentDynamic loading
  • The child applicationjumpThe parent application
  • Style isolation

The transformation has officially begun.

The micro front-end framework is used in Qiankun. As the framework we use is Umi, the plugin @umijs/plugin-qiankun is provided correspondingly.

The main application

  1. Enable the Configuration in the UMI configuration file qiankun
  qiankun: {
    master: {},
Copy the code
  1. Loader application configuration
Function microApp(entryPrefix) {return [{name: 'entryPrefix ', // id: entryPrefix?' ${entryPrefix}/app1 ': ${entryPrefix}/app2 ': ${entryPrefix}/app2' : ${entryPrefix} '//localhost:3001',}... // other child applications]; } export default microApp;Copy the code
  1. Configure the route of the active sub-application
Const router = [{path: '/main/app/rouer/app1', // (/main/app/rouer/) microApp: 'app1', microAppProps: { autoSetLoading: true, className: 'appClassName', wrapperClassName: 'wrapperClass', }, }, { path: '/main/app/rouer/app2', microApp: 'app2', microAppProps: { autoSetLoading: true, className: 'appClassName', wrapperClassName: 'wrapperClass',},}... export default router;Copy the code
  1. In entry fileapp.jsExport the Qiankun object
import microApp from './microApp';
import router from './router';

export const qiankun = new Promise((resolve) => {
  const entryPrefix = process.env.NODE_ENV === 'production' ? window.location.origin : null;
  const res = microApp(entryPrefix);
}).then(apps => {
  return {
    routes: router,
Copy the code

The child application

  1. Example Enable configuration qiankun in UMI
  qiankun: {
    slave: {},
Copy the code
  1. In entry fileapp.jsExample Export the life cycle of Qiankun
Export const qiankun = {// async bootstrap(props) {init(props); }, // trigger async (props) {}, // trigger async unmount(props) {};Copy the code

Based on the Qiankun and Umi provided qiankun plug-in is more convenient to run up. Let’s see how to solve the problem above.

Solve some problems encountered in practice

Component library upgrade, support ANTD4.x

We use incremental refactoring. We need the ability to upgrade increments, to get old and new code to work together, and then gradually transform old code until the refactoring is complete. We are currently upgrading the component library based on the antd3.x version to 4.x. Both versions are updated at the same time for a period of time. The two versions can coexist, and the migrated child application uses ANTD 4.x to ensure that we can use the new features

Master application communication

The Umi Qiankun Plugin provides a way for host apps to communicate with each other

Export from the main application portaluseQiankunStateForSlavemethods

export function useQiankunStateForSlave() {
  const [masterState, setMasterState] = useState({});

  return {
    // masterState,
Copy the code
The child application automatically generates a global model that can obtain the props value of the main application transparently from any component.
import { useModel } from 'umi';

function MyPage() {
  const masterProps = useModel('@@qiankunStateFromMaster');
  return <div>{JSON.stringify(masterProps)}</div>;
Copy the code

There is no problem with communication between master and sub-applications in this way, but it is not very convenient to use nested multi-layer sub-applications. We will transform it later

The primary application shares some instances for the sub-applications to use

In microfront-end architecture, it is not recommended to share instances of applications, because it would be difficult to develop and deploy independently, and the application would be coupled. However, since we split the system, some common functions, such as viewing logs in the pop-up box and data preview, will first use the functions of the parent application, which need to be shared. Here we encapsulate the SDK for use by sub-applications. Later if you want to transform this piece into independent development, independent deployment. We implement the corresponding interface, dynamic injection, can be implemented.

  • Define the method to share logs
Class Log {show = (params) => // service logic} showOther = (params) => {// service logic}} export default new Log();Copy the code
  • Create in the main applicationSlaveSDKThe instance
import intl from 'utils/intl'; import { history } from 'umi'; import { getParams } from 'utils/util'; import Log from './log'; class SlaveSDK { constructor() { this.log = Log; this.intl = intl; This. router = {history, // getParams, // get the main application parameters}; . }} export default new SlaveSDK();Copy the code
  • It is passed to the child application through data communication
import SlaveSDK from './SlaveSDK';
export function useQiankunStateForSlave() {
  return {
Copy the code
  • The child application gets the SDK and initializes and saves it during the lifecycle
Export const qiankun = {// async bootstrap(props) {props? .SlaveSDK && setSDK(props.SlaveSDK); }};Copy the code

Some data in the Redux Store needs to be shared. How do I limit this

The sub-application business may need some data from the Redux Store, but we can’t expose the whole Store to the sub-application, so we can restrict the use of the application. Here we use proxy objects to achieve this

const allowGet = { auth: '', user: '' }; Const state = getReduxStore(); const proxy = new Proxy(state, { get(target, property) { if (property in allowGet) { return target[property]; } return undefined; }}); return proxy; };Copy the code

Sub-applications support internationalization and internationalized content is dynamically loaded

We get intL of the internationalization instance by sharing the instance and through SDK, and load internationalization when the child application is initialized.

/** * internationalization initialization */ const intlInit = async () => {// load language file const result = await import('./locales'); const intl = await import('./utils/intl'); try { moment.locale(intl? .default?.getIntlLang?.() || 'zh_CN'); intl? .default?.load(result.default); } catch (error) { console.error('intl error', error); }};Copy the code

The child application jumps to the parent application

The route to the parent in the child is also passed to the child by passing the history object of the parent’s router

import { history } from 'umi'; Class SlaveSDK {constructor() {this.router = {history, // getParams, // getParams, // getParams}; }}Copy the code

Style isolation

We are using cssModule, which automatically generates a unique key at compile time. The main problem is ANTD, because we have loaded both ANTD3 and ANTD4, resulting in a style conflict. I changed the prefix when ANTd4 was compiled. Configuration is as follows

import { ConfigProvider } from 'antd'; ConfigProvider. Config ({prefixCls: 'my-ant',}); <ConfigProvider prefixCls="my-ant">Copy the code

The deployment of

The system uses nGINx deployment, which is handled in the same Server through different paths. Configuration is as follows

server { listen 8080; server_name localhost; location / { root html; index index.html index.htm; try_files $uri $uri/ /index.html; } location /app1 { root html; index index.html index.htm; try_files $uri $uri/ /app1/index.html; } location /app2 { root html; index index.html index.htm; try_files $uri $uri/ /app2/index.html; }}Copy the code


The first version of the micro front end is currently online, and it is possible that the next version will have nested multi-layer sub-applications. The following issues need to be addressed

  • Resource isolation
  • Multiple layers of nested applications share state
  • Combine WebPack5 Module Federation and Qiankun to isolate resources
  • As the number of sub-applications increases, the scaffolding is enhanced


In this version, the scaffolding completes the basic functionality of generating our sub-applications from the modules. After the late enhancement, the main application and sub-application can be generated, which will share this piece. Above is the micro front end landing this summary of some problems, if there are problems, welcome to correct.


  • umi
  • qiankun
  • umijs/plugin-qiankun