使用@umijs/plugin-qiankun搭建微前端应用(2)——MicroApp组件

301 阅读2分钟

装载子应用的两种方式

子应用的装载有两种方式,我们上一节讲了第一种方式,使用路由绑定的方式:

import { defineConfig } from 'umi';

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  fastRefresh: {},
  qiankun: {
    master: {
      // 注册子应用信息
      apps: [
        {
          name: 'app1',
          entry: 'http://localhost:8001',
        },
        {
          name: 'app2',
          entry: 'http://localhost:8002',
        },
      ],
      // 配置微应用关联的路由
      routes: [
        {
          path: '/app1',
          microApp: 'app1',
        },
        {
          path: '/app2',
          microApp: 'app2',
        },
      ],
    },
  },
});

今天我们来讲解另一种子应用的装载方式,使用 组件的方式。

官方文档中建议使用第一种方式来引入自带路由的子应用。使用第二种方式来引入不带路由的子应用。否则使用第二种方式需要自行关注微应用依赖的路由跟当前浏览器 url 是否能正确匹配上,不然很容易出现微应用加载了,但是页面没有渲染出来的情况。

在实践中我们发现第二种方式有个很重要的优势,就是在父子应用通信中可以很方便地支持动态数据的传递(应用通信会在第 3 节介绍),所以我们的微前端应用的子应用装载实际使用的是第二种方式。

使用 <MicroApp /> 组件装载子应用

修改 umi 配置文件:

import { defineConfig } from 'umi';
import { APP_LIST } from './src/constants';

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  fastRefresh: {},
  qiankun: {
    master: {
      // 注册子应用信息
      apps: APP_LIST,
    },
  },
});

其中 APP_LIST 的值为:

import { IApp } from '@/types';

export enum EAppPath {
  app1 = '/qiankun-app1',
  app2 = '/qiankun-app2',
}

export const APP_LIST: IApp[] = [
  {
    name: 'app1',
    entry: 'http://localhost:8001',
    path: EAppPath.app1,
  },
  {
    name: 'app2',
    entry: 'http://localhost:8002',
    path: EAppPath.app2,
  },
];

编写使用<MicroApp />组件装载子应用的逻辑:

import React, { useMemo } from 'react';
import { Link, useLocation, MicroApp } from 'umi';
import { APP_LIST, EAppPath } from '@/constants';

const Layout: React.VFC = () => {
  const location = useLocation();
  const pathname = location.pathname;

  const app = useMemo(() => {
    const app = APP_LIST.find((item) => item.path === pathname);
    return app;
  }, [pathname]);

  const hasApp = () => {
    return Boolean(app?.name);
  };

  const appPathKeys = Object.keys(EAppPath) as (keyof typeof EAppPath)[];

  return (
    <div>
      <div>
        {appPathKeys.map((key) => {
          const path = EAppPath[key];
          return (
            <div key={key}>
              <Link to={path}>{path}</Link>
            </div>
          );
        })}
      </div>
      {hasApp() && <MicroApp name={app?.name} />}
    </div>
  );
};

export default Layout;

这样,就完成子应用的装载啦。

微应用的 loading 动画与组件样式

你可以通过配置 autoSetLoading 的方式,开启微应用的 loading 动画。

<MicroApp name={app?.name} autoSetLoading />

默认情况下,当检测到你使用的是 antd 组件库时,loading 动画使用的是 antd Spin 组件。

如果你需要定制自己的 loading 动画,或者修改组件的样式,你可以这样处理:

<MicroApp
  name={app?.name}
  autoSetLoading
  // 设置自定义 loading 动画
  loader={(loading: boolean) => {
    if (!loading) {
      return null;
    }

    return <div>loading</div>;
  }}
  // 微应用容器 class
  className="myContainer"
  // wrapper class,仅开启 loading 动画时生效
  wrapperClassName="myWrapper"
/>