Skip to content

03. 基座声明式路由

Vizards edited this page Nov 12, 2020 · 2 revisions

Ming 将整个微前端站点的路由收归到基座路由控制,但仍然需要各个子应用配置自己应用内的路由。

核心需求点满足

  1. 声明式的路由级权限控制体系;
  2. 声明式且支持自定义的路由重定向功能;
  3. path-to-regexp 驱动的动态路由体系。

集中式权限路由

由于权限和路由天然的相关性,Ming 尝试将权限数据和路由数据聚合在一起。1.1.0 版本开始,权限、路由和微前端应用的配置全部集中到基座应用的config.[env].ts 中,以适应更灵活和动态化的管理方案。

增强后的子应用权限路由数据示例:

const subApps: MingRoute[] = [
  {
    path: '/',
    redirect: '/home',
    sidebar: false,
  }, // 这是一个自动重定向配置,不代表任何子应用
  {
    name: 'account',
    microApp: 'account',
    entry: 'http://localhost:3010',
    path: '/account',
    title: '账户',
    wrappers: ['@/wrappers/brother'], // 一个 brother 级子应用
    routes: [ // 子应用自己的路由注册到这里
      {
        path: '/account/login',
        title: '登录',
      },
    ],
  },
  {
    name: 'home',
    microApp: 'home',
    entry: 'http://localhost:3000',
    path: '/home',
    title: '首页',
    wrappers: ['@/wrappers/children'],
  },
  {
    name: 'car',
    microApp: 'car',
    entry: 'http://localhost:3001',
    path: '/car',
    title: '车辆数据',
    /* 父级菜单和子菜单的权限,有单独的一套控制逻辑 */
    privilegeId: '查看车辆数据',
    wrappers: ['@/wrappers/children'],
    routes: [
      /* 简单的固定路由 */
      { path: '/car/all', title: '全部车辆', privilegeId: '查看全部车辆' },
      {
        path: '/car/overproof',
        title: '超标车辆',
        privilegeId: '查看超标车辆',
      },
      {
        path: '/car/detail/:id', // 支持 path-to-regexp 规则的动态路由
        title: '车辆详情',
        sidebar: false,
        privilegeId: '查看车辆详情',
      },
      /*
       * 当一个 route 没有 path 时,它是一个纯粹的权限数据
       */
      {
        sidebar: false,
        title: '异步按钮',
        privilegeId: '查看异步渲染的按钮',
      },
    ],
  },
  {
    name: 'oss',
    microApp: 'oss',
    entry: 'https://cloud.vizards.cc/ming/oss/index.html',
    path: '/oss',
    title: 'OSS 页面',
    privilegeId: '查看OSS页面',
    wrappers: ['@/wrappers/children'],
  },
];
  • 约定 route.privilegeId 是该菜单/权限项对应的权限 ID;
  • route 没有 privilegeId 字段时,认为所有用户都有访问到此 route 的权限 (在权限系统设计中,如果所有用户都不可访问此路由,应该后台配置所有用户没有此权限 ID 即可);
  • route 没有 path 字段时,不作为路由处理,它是一个纯粹的权限数据。

子应用左侧 Menu 父菜单和子菜单的权限控制逻辑

具体控制逻辑代码参见:

  1. 根菜单项设置的 path 不可以被直接访问到,仅作为生成侧边菜单栏使用

  2. 当一个子菜单项需要显示在 Menu(即 sidebar 不为 false),并且权限允许该子菜单显示时(即对应的 privilegeId 被勾选)时:父菜单也相应显示

  3. 一个父菜单项的所有子菜单项都不需要显示在 Menu(即子菜单项要么 sidebar 为 false, 要么权限不允许显示),则父菜单项也不会显示

  4. 只要一个父菜单项的其中一个子菜单项需要显示在 Menu, 父菜单项也会相应显示

  5. 如果一个父菜单项的不需要显示在 Menu(即此父菜单项的 sidebar 为 false,且权限不允许此父菜单显示),将无视此父菜单项所有子菜单的配置,一律不显示在 Menu

不同的子应用如何互相跳转/通信?

fundation/src/app.ts 中暴露了基座应用的 history API 供子应用使用 @@qiankunStateFromMaster 这个自动生成的全局 model 调用。

例如,在子应用 account 中,account/src/pages/login.tsx 的使用示例如下:

import { useModel } from 'umi';

const { rootHistory } = useModel('@@qiankunStateFromMaster')

此时这个 rootHistory 就是基座应用 fundationhistory 了。

使用同样的方式,可以将任何需要暴露给子应用的全局数据或方法在 fundation/src/app.ts 定义并导出。